java - 如何在 Spring 反应式处理程序函数中提取请求正文?
问题描述
我正在使用 Spring Web Flux 实现处理程序函数,并希望提取x-www-form-urlencoded
POST-Body 的值。
public Mono<ServerResponse> handle(ServerRequest incomingHttpRequest) {
Mono<MultiValueMap<String, String>> formData = incomingHttpRequest.body(BodyExtractors.toFormData());
return formData
.doOnEach(signal -> {LOG.info("EACH: " + signal.getType());})
.doOnSubscribe(x -> {LOG.info("SUBSCRIBED");})
.doOnNext(next -> {LOG.info("NEXT: " + next);})
.doOnError(x -> {LOG.info("ERROR: " + x.getMessage());})
.doOnSuccess(x -> {LOG.info("SUCCESS: " + x);})
.flatMap(multiValueMap -> ServerResponse
.badRequest()
.body(BodyInserters.fromObject(
"searchTerm: " + multiValueMap.getFirst("searchTerm")
))
);
}
处理程序被添加到路由器,如:
return RouterFunctions.route(RequestPredicates.POST("/mysearch"), searchHandler::handle);
通过 Postman 发送带有 Body searchTerm=something&lang=de 的 POST 会得到以下结果:
o.s.w.s.adapter.HttpWebHandlerAdapter : [f405c02b] HTTP POST "/mysearch"
o.s.http.codec.FormHttpMessageReader : [f405c02b] Read form fields [searchTerm, lang] (content masked)
o.s.w.r.f.s.s.RouterFunctionMapping : [f405c02b] Mapped to de.myproject...
de.myproject.MyHandler : SUBSCRIBED
de.myproject.MyHandler : EACH: onComplete
de.myproject.MyHandler : SUCCESS: null
o.s.w.s.adapter.HttpWebHandlerAdapter : [f405c02b] Completed 200 OK
我希望得到一个包含 searchTerm 的 BAD_REQUEST。但是我得到了200。
对我来说,看起来生成的 Mono 已被订阅,然后成功完成。但formData
永远不会收到值,因此永远不会进入flatMap(...)
我在做错什么映射Mono<MultiValueMap<String, String>>
到 a Mono<ServerResponse>
?
解决方案
这里有两件事在起作用:
- 您只被允许订阅(即阅读)请求正文一次的事实
- 从请求中获取表单数据需要读取和解析它
在 Spring Boot 2.0.x-2.1.x 中,HiddenHttpMethodFilter
默认启用。此过滤器对于使用 HTML 表单中浏览器本身不支持的 HTTP 方法(如“DELETE”)很有用。如果传入请求属于该类型,则此过滤器需要解析表单数据。
可以说,这种用例越来越少见,并且从 Spring Boot 2.2 开始默认禁用。
现在在您的示例中,读取和解析传入请求将不起作用,因为它已被过滤器解析。禁用过滤器将解决该问题。
但更好的解决方法是使用专用方法request.formData()
,它将解析和缓存结果(如果多次调用,则返回已解析的数据)。
推荐阅读
- powerapps - 如何将数据从 PowerApp 发送到 Flow Automate (POST)?
- java - Android - 即使方法完成后如何不销毁监听器对象?
- sql - 在 postgres 中创建具有差异列的视图
- kubernetes - prometheus 查询以按标签拉取 kubernetes 节点并仅列出某些字段
- c++ - C++20 的 std::vector 如何分配 constexpr?
- excel - 获取图表 Y 轴的中点
- c++ - 如何让“cin”读取原始模式终端
- javascript - 将 html 值放入 onClick()
- python - 如何将海岸线添加到 xarray.plot.facetgrid.FacetGrid?
- power-automate - Power Automate - 无法导航到文件夹或获取文件夹 ID