ajax的发post请求的坑

Posted by 小拳头 on Monday, September 20, 2021

在前端通过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', 去使得请求体不是对象的形式.

参考

  1. POST方法

comments powered by Disqus