这是我参与更文挑战的第23天,活动详情查看:更文挑战
[重学JavaScript系列文章连载中…]
问题
前端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){
}
});
复制代码
后端接口定义:
public
复制代码
理想认为接口可以接收成功,但实际上并没有。
原因
这是因为,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']
}
复制代码
总结
至此我们学习了序列化与反序列化。