经常碰到ajax请求传参,后端接收不到的问题。之前只是模糊的指导,前端传参格式与后端一致就可以。大多数就是直接拷贝已有的前后端代码做修改,没有深入、系统的了解过这块的东西。今天想了解了,却又不知道从何入手了。想了想,觉得从http协议入手比较好。
HTTP协议
整体的流程是:
- 客户端构造http请求(依据http协议的要求和自身需求,构造一定结构的数据)
- 发送数据(1中构造的结构数据,通过网络发送出去)
- 服务器接收数据并解析,然后返回一定结构的数据
- 客户端接收返回的数据并解析
请求协议结构:
- 请求行:请求方法 URL 协议版本
- 请求头:多行键值对
- 空行 :
- 请求体:任意的内容:字符串、二进制数据
我们发起ajax请求时,最终都是构造成了这样的结构。
所以我们需要考虑的是,我们前端构造的数据是怎样的,后端需要的数据是怎样的。协议结构中,我们传业务相关的数据一般有两个位置。
- 请求行中的URL中,在?后面:key1=value1&key2=value2的形式传
- 请求体。可以是任何格式,但是为了前后端统一,会在请求头的content-type中保存下请求体保存的数据格式。
AJAX构造HTTP请求协议结构
前端浏览器、或者提供ajax请求的库,会将我们写的代码构造成http请求协议结构。以jquery为例:
$.ajax({
url:"/path?a=1&b=2",
method:"post",
data:{},
contentType:""
})
最重要的就是上面的四个参数。
$.ajax({
url:"/path?a=1&b=2",
method:"get",
data:{}
})
$.ajax({
url:"/path?a=1&b=2",
method:"post",
data:{},
})
$.ajax({
url:"/path?a=1&b=2",
method:"post",
data:JSON.stringify({c:1}),
contentType:"application/json"
})
method默认为get时:
- contentType不起作用。
- data中的数据最终会自动追加到url的后面。
- data是对象时,会按属性拆成键值对进行追加
meghod为post时:
- contentType起作用(传到服务器端起作用,默认为“application/x-www-form-urlencoded; charset=UTF-8”。在解析中好像不起作用。在浏览器的调试窗口中,会用来解析请求数据的展示结构)
- data中的数据会添加到请求体中。
- data是对象时,会按属性拆成key1=value1&key2=value2形式
- data是字符串时,不解析
所以我们前端jquery构造的http请求协议数据常用的有一下三种:
1
get URL+kv数据2
post URL+kv数据
content-type:‘application/x-www-form-urlencoded’
body:kv数据(key1=value1&key2=value2)3
post URL+kv数据
content-type:‘application/json’
body:json字符串( ‘{“key1”:value1,“key2”:vlaue2}’ )
服务器端接收
服务器接口会解析URL后的数据,请求体中的数据。然后依据content-type进行解析。这里以springboot为例。
依次对应上面客户端构造的结构:
key1=value1&key2=value2这种的value本质传个字符串。你也可以传个json格式的字符串。springboot后端可以直接使用字符串接收,然后转换成相关类型。不知道springboot是不是也可以自动进行转换。试了下好像可以自动转数组,map和实体类的好像转不了,可能提供了自定义转换实现的入口。
@RequestMapping(value = "/test1", method = RequestMethod.POST)
@ResponseBody
public String test1(@RequestParam(item) String item) {
return "";
}
@RequestMapping(value = "/test2", method = RequestMethod.GET)
@ResponseBody
public String test2(@RequestParam(name) String name) {
return "";
}
@RequestMapping(value = "/test3", method = RequestMethod.POST)
@ResponseBody
public String test3(@RequestBody Item item) {
return "";
}
总结下
前端jQuery,后端springboot的。直接这么用就成。
$.ajax({
url:"/path?a=1&b=2",
method:"get",
data:{}
})
$.ajax({
url:"/path",
method:"post",
data:{
name:"zhangs"
},
})
$.ajax({
url:"/path",
method:"post",
data:JSON.stringify({c:1}),
contentType:"application/json"
})
@RequestMapping(value = "/test1", method = RequestMethod.GET)
@ResponseBody
public String test1(@RequestParam(a) String a,@RequestParam(b) String b) {
return "";
}
@RequestMapping(value = "/test2", method = RequestMethod.POST)
@ResponseBody
public String test2(@RequestParam(name) String name) {
return "";
}
@RequestMapping(value = "/test3", method = RequestMethod.POST)
@ResponseBody
public String test3(@RequestBody Item item) {
return "";
}
补充
前端有时会用FormData构造参数。一般是post请求中,FormData数据会使用分割符,分割符需要在content-type中注明。
此时需要的ajax请求中需要processData和ontentType都设置为false。它会自动将content-type设置为:“multipart/form-data; boundary=----WebKitFormBoundaryWJwK1ZIKGijfvNQk”,“----WebKitFormBoundaryWJwK1ZIKGijfvNQk”这就是分隔符,好像是自动生成的。
$.ajax({
url:"",
data:d2,
processData: false,
contentType:false,
method:'post'
});
@RequestMapping(value = "/test2", method = RequestMethod.POST)
@ResponseBody
public String test2(@RequestParam(name) String name) {
return "";
}