Request Payload 和 Form Data 的区别
概述
我正在开发的项目前端和后端是完全独立的,通过配置 webpack 的 proxy 将前端请求跨域代理到后台服务。昨天发现,我前端执行 post
请求,后台 springmvc 的 @RequestMapping
接收不到对应的请求参数。开始我以为是我 proxy 配置有问题,导致 post 参数不能传到后台。然而,并不是这样…
proxy 配置如下:
前端代码:
java 后台代码:
Request Payload VS Form Data
前端请求
我看了前端发起的请求,请求正文并不是我熟悉的 Form Data
,而是 Request Payload
Request Payload 大概格式如下,请求头部的 Content-Type: application/json
,并且请求正文是一个 json 格式的字符串
Form Data 大概格式如下,请求头部的 Content-Type: application/x-www-form-urlencoded
,并且请求正文是类似 get 请求 url 的请求参数
后台处理
对于 Request Payload 请求, 必须加 @RequestBody
才能将请求正文解析到对应的 bean 中,且只能通过 request.getReader()
来获取请求正文内容
对于 Form Data 请求,无需任何注解,springmvc 会自动使用 MessageConverter 将请求参数解析到对应的 bean,且通过 request.getParameter(...)
能获取请求参数
解决方案
综上,我在前端选择使用 Form Data 的方式来发起请求,使用 qs 库将 json 对象转化为字符串 (如 {name:'dahuang',age: 11}
转化为 name=dahuang&age=11
)。
之前我以为 axios 会自动根据你的请求正文格式来选择发起 Form Data 还是 Request Payload 请求,但是执行 delete 操作时,如图的 Content-Type 却是 text/plain
所以,通过通过下面的方面来解决
一个奇怪的问题
执行 delete 操作时,我将 axios 添加了 headers,content-type: 'application/x-www-form-unlencoded'
,请求如图,但是后台 springmvc 的 @DeleteMapping
接收不到请求参数,必须使用 @RequestParam String id
,才能接收到请求参数。看了这个回答,有人回复说这个是 tomcat 的问题而非 spring 的问题。
更新,今天遇到了一个问题,突然我的 @PatchMapping
也不能获取 form 表单传递的参数了。之前是可以的,然后我 google 搜到了 HttpPutFormContentFilter,然后发现这个 filter 在 WebMvcAutoConfiguration
里面配置的,而这个配置生效其中有一个条件是 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
,恰好,我前两天整合前端代码的时候配置 springMVC 继承了 WebMvcConfigurationSupport.class
所以导致了该 fliter 不生效。