概述
我正在開發的項目前端和后端是完全獨立的,通過配置 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 不生效。