ajax的发post请求的坑

在前端通过ajax请求向服务端发送请求是非常常见的场景, 在Java Web开发中, 通常用SpringMVC去取得请求体的数据. 而用ajax做post请求, 用的工具通常是jquery或者vue中推荐的axios. 但是这两者装载post请求体的方式其实是不同的, 这是个小小的坑, 做个小实验看看.
后端就是一个平平无奇的ajaxIndexPage做html文件的跳转, handleAjaxRequest作为接口响应前端请求. 我们用@RequestParam注解去取得post的data, 总所周知, 这个注解只能取到url?xxx=1&xxx=2这样的数据.
@Controller public class AjaxController { @RequestMapping(value = {"/", "/index"}) public String ajaxIndexPage() { return "ajax-test/index"; } @RequestMapping("/api/ajax-query") @ResponseBody public String handleAjaxRequest(@RequestParam(value= "requestNumber", defaultValue = "0") Integer requestNumber) { System.out.println("the number is " + requestNumber); return "good"; } }
前端页面更加平平无奇, 用两个按钮发送jquery post和axios post, 看似请求时一模一样的, 也就是说, 后端如果能拿到requestNumber, 就证明请求的data成功被@RequestParam注解拿到了, 如果没有拿到, 那么后端的requestNumber就会是默认值0.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <button @click="query1">jquery</button> <button @click="query2">axios</button> </div> </body> <!--注意这里的路径不能带static--> <script src="../../vue.min.js"></script> <script src="../../jquery-3.6.0.min.js"></script> <script src="../../axios.min.js"></script> <script type="module"> new Vue({ el: '#app', methods: { query1() { $.ajax({ url : "/api/ajax-query", type : "POST", contentType : "application/x-www-form-urlencoded", dataType : "json", data: { requestNumber: 1 }, success: function (response) { debugger; console.log(response); }, }); }, query2() { axios({ url: '/api/ajax-query', method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, data: { requestNumber: 2 } }).then(function (response) { debugger; console.log(response); }); } }, }) </script> </html>
接下来就是开心的实验时刻, 会发现jquery post让后端输出了the number is 1, 而axios post让后端输出了the number is 0, 一个成功了, 一个不成功, 这是怎么回事呢. 首先从chrome的开发者工具入手, 发现请求响应本身是没有问题的, 而问题就出在post是如何装载数据的, 为了清楚地看到post请求主题是什么样的, 我们用wireshark抓包试试. 选择Loopback: lo0就能抓去本地的请求响应.
上图是jquery post的请求体, 下图是axios post的请求体. 前者是类似url?xxx=1&xxx=2的形式, 而后者是一个对象的形式. 所以说, 如果用axios做发送请求的工具, 想让后端通过@RequestParam去拿到请求中的字段, 我们还是只有通过写data: 'requestNumber=2', 去使得请求体不是对象的形式.
notion image
notion image

参考

  1. POST方法