在前後端聯調過程中,常常會遇到前端同學説“明明向後端傳遞了數據,怎麼後端接收不到呢?”為了解決這個困擾,本文來分析下究竟是什麼導致了上述問題。
前後端聯調時常會F12打開調試器分析請求,在request body中通常會看到Form Data與Request Payload兩種形式。
場景
- 使用
axios發送post請求,參數為對象,默認會設置Content-Type為application/json。
- 使用
axios發送post請求,參數為對象,手動設置Content-Type為application/x-www-form-urlencoded。
- 使用
axios發送get請求,默認會設置Content-Type為application/x-www-form-urlencoded。
- 使用
form表單發送get請求,encType設置為application/x-www-form-urlencoded,如果沒有設置encType,默認值為application/x-www-form-urlencoded。會自動對錶單數據URL編碼,並以鍵值對形式追加到請求url後面,表單提交後會跳轉到新url。如果這種形式上傳文件肯定是不行的,將文件對象轉化成Data url然後追加到url後面,如果文件比較大,dataurl也會很長,追加到url後面可能會超出url最大長度。
- 使用
form表單發送post請求,encType設置為application/x-www-form-urlencoded。會自動對錶單數據URL編碼,並編碼成鍵值對形式。如果以這種形式上傳文件,傳輸性能比較差(字符傳輸性能比二進制傳輸性能差)。
- 使用
form表單發送post請求,encType設置為multipart/form-data。
- 使用
FormData封裝數據,axios發送post請求,Content-Type設置為multipart/form-data。
tomcat對請求參數做了一些處理
詳情可以參考這兩篇文章,結合起來看可以得出下面結論
tomcat的servlet讀取請求參數
tomcat源碼---->request的請求參數分析
1、對於get請求參數,tomcat會將參數以鍵值對形式放進一個名叫paramHashValues的Map中,後端通過request.getParameter(name)取的就是paramHashValues裏面的數據,或者使用springMVC中的@RequestParam。
2、對於post請求,Content-Type為application/x-www-form-urlencoded,請求參數也會放進一個名叫paramHashValues的Map中,後端通過request.getParameter(name)取的就是paramHashValues裏面的數據,或者使用springMVC中的@RequestParam。
3、對於post請求,Content-Type為multipart/form-data,tomcat通過request.getInputStream().read()讀取請求數據流,然後放入到paramHashValues當中。後端可以通過((MultipartHttpServletRequest) request).getFiles("file")來獲取上傳文件對象,至於其他的表單參數,通過((MultipartHttpServletRequest) request).getParameter(name)來獲取;或者使用springMVC中註解@RequestParam和MultipartFile來接收:
4、對於post請求,Content-Type為application/json,不會將請求參數放入到paramHashValues當中,因此request.getParameter(name)是獲取不到參數值。需要通過註解@RequestBody來接收參數。
因此,後端為什麼接收不到前端傳的參數,主要是因為前端設置的Content-Type與後端接收參數的方式(request.getParameter(name)或者其他)不一致。
附上@RequestBody和@RequestParam區別
實際項目中的一些場景
1. post請求,Content-Type為application/x-www-form-urlencoded
2、post請求,Content-Type為application/json
3、form表單post請求,默認Content-Type為application/x-www-form-urlencoded
4、form表單post請求,Content-Type為multipart/form-data