问题
前端 ajax 请求发送数组,后端接口接到到为 null,这问题应该很经常碰到,这里来重温下。
前端 Ajax 请求:
let data = {
ids:[1,2,3,4]
}
// 普通的post,只不过里面是ids数组
$.ajax({
type:"POST",
url:"user/saveUser",
dataType:"json",
contentType:"application/json",
data:data,
success:function(data){
}
});
复制代码
后端接口定义:
理想认为接口可以接收成功,但实际上并没有。
原因
这是因为,ajax 请求默认对参数进行了深度序列化,然而 servelt api 无法处理这个,这也就导致了接口接收到的为 null。深度序列化后接口参数为:ids[]=1&ids[]=2&ids[]=3
,通过 ids 自然就获取不到了。
解决办法
解决这个问题的方法有如下:
通过给 ajax 请求设置:traditional:true
,使用传统的方式浅层序列化(参数序列化),此时传递的数据参数为:ids=1&ids=2&ids=3
。接口无需修改,可直接获取参数。
将传递的数组转为字符串,通过字符串进行传输。{ids:JSON.stringify([1,2,3])}
,此时后端接口需要做相应的调整。
知识扩展
JSON 序列化
JSON 序列化是将 JSON 对象处理为 JSON 字符串的过程,以方便数据传输。可以通过JSON.stringify()
或者对象自定义toJSON()
函数来实现。
JSON.stringify()函数
用法如下:
// object:要序列化的对象
// replacer:可选参数,若为函数,表示序列化过程中,被序列化的每个值都会经过该函数处理。
// 若为数组,则表示只有存在数组中的属性,才参与序列化。
// space:可选参数,指定缩进的空白字符串,美化输出。最小值是1,上限值是10.
JSON.stringify(object,replacer,space)
复制代码
举个例子:
var obj = {
name:'zhangsan',
age:12,
hobits:['ball','games']
}
// 1. 自定义个函数
var replacer = function(key,value){
if(typeof value==='string'){ // 将字符转为大写
return value.toUpperCase()
}
return value
}
//输出: {name:'ZHANGSAN',age:12,hobits:['BALL','GAMES']}
JSON.stringify(object,replacer)
// 2. 自定义数组
var replacer = ['name']
// 输出:"{"name":"zhangsan"}"
JSON.stringify(object,replacer)
复制代码
为什么数组也转换成大写字母了呢?
JSON 序列化时,如果属性为对象或者数组,则会继续序列化该属性值,直到属性值为基本类型、函数或者 Symbol 类型才结束。
自定义 toJSON()函数
如果被序列化的对象拥有 toJSON()函数,那么 toJSON()函数会覆盖默认的序列化行为,被序列化的值将变成是 toJSON()函数的返回值。它可以更精确的控制序列化,可以理解为是对 stringify 函数的补充。
var object = {
name:'张三',
age:12,
city:'北京',
toJSON:function(){ // 这里不能使用箭头函数,因为执行object.toJSON()将继承父作用域,this不指向object
return {
Name:this.name,
Age:this.age
}
}
}
JSON.stringify({name:object},['name'])
// 输出的是:"{"name":{}}"
复制代码
object.toJSON()后返回的是{"Name":"张三","Age":12},此时序列化变化{"name":{"Name":"张三","Age":12}}
第二个参数 replacer 是数组["name"],此时过滤的是 name 属性,但 name 属性是个对象,因此对对象的属性进行递归序列化,而这里的属性不存在 name,所以过滤 后就为一个空对象{}。
JSON 反序列化
JSON 反序列就是将 JSON 字符串转换为 JSON 对象的过程,这里存在两种方式,一种是通过 JSON.parse()函数,另一种是通过 eval()。
JSON.parse()
基本用法如下:
// text: 接收的json字符串
// reviver: 可选参数,若为函数,则规定了原始值在返回之前如何被解析改造。
JSON.parse(text,reviver)
复制代码
例子如下:
var text = "{"name":"zhangsan","age":12,"hobits":["ball","games"]}"
JSON.parse(text,function(key,value){
if(key==='name'){
return value+'同学'
}
return value
})
// 输出:
{
name:'zhangsan同学',
age:12,
hobits:['ball','games']
}
复制代码
eval()函数
eval()函数用于计算 JavaScript 字符串,并把它当作脚本来执行。
var text = '{"name":"zhangsan","age":12,"hobits":["ball","games"]}'
var object = eval("("+text+")")
// 输出:
{
name:'zhangsan',
age:12,
hobits:['ball','games']
}
复制代码
总结
至此我们学习了序列化与反序列化。
评论