先来确定一个事情:
let a = [1]
let b = JSON.stringify(a) // '[1]'
let c = encodeURIComponent(b) // '%5B1%5D'
let d = encodeURIComponent(c) // '%255B1%255D'
这里需要留意一下a
、b
、c
、d
转码之后的格式,后面会用到。
然后问题来了,现在需要和后端对接一个接口,在swagger
调试的结果类似这样
https://www.baidu.com/s?arr=%5B1%5D
经过分析可以看出%5B1%5D
是encodeURIComponent(JSON.stringify([1]))
之后的结果。
那么前端可以用axios
对接接口,例如:
axios({
url: 'https://www.baidu.com/s',
method: 'get',
params: {
arr: encodeURIComponent(JSON.stringify([1]))
},
})
但是在谷歌浏览器上点击F12,你会发现发送出去的链接是:
https://www.baidu.com/s?arr=%255B1%255D
%255B1%255D
是encodeURIComponent(encodeURIComponent(JSON.stringify([1])))
之后的结果。
这里大家可能会想,这个应该是axios
内部进行了转码造成的,那我们再来看一下这个例子:
axios({
url: 'https://www.baidu.com/s',
method: 'get',
params: {
arr: JSON.stringify([1])
},
})
这个链接会输出什么呢,如果结果是https://www.baidu.com/s?arr=%5B1%5D
,那么就能证明,确实是axios内部进行了转码,但是结果很奇怪,输出的链接是https://www.baidu.com/s?arr=[1]
,竟然没有进行转码!
也就是在使用axios时候,parms的参数是{arr: JSON.stringify([1])}
时,url不转码。parms的参数是{arr: encodeURIComponent(JSON.stringify([1, 2, 3]))}
时,会进行转码!
我们只能打断点看一下源码了!
git clone https://github.com/axios/axios.git
我clone的axios版本是1.4.0
可以看到axios里面使用的是XHR,也就是ajax,在我画红框的地方有一个buildURL方法,然后把params传入了这个方法,来看一下buildURL具体实现
可以看到里面有一个encode
方法,里面还是用到了encodeURIComponent
,也就是说对于放在params里面的内容,都会转码,至于为什么JSON.stringify([1])
没有被转码,其实可以看一下这句话:
function encode(val) {
return encodeURIComponent(val).
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%20/g, '+').
replace(/%5B/gi, '[').
replace(/%5D/gi, ']');
}
也就是说JSON.stringify([1])
先被转码为‘%5B1%5D’
,然后遇到了replace(/%5B/gi, ‘[’)
和replace(/%5D/gi, ‘]’)
,所有就又转回了[1]
。
那么如何阻止axios的自动转码呢?这里给出3中方法。
paramsSerializer
修改默认行为,例如:axios({
url: 'https://www.baidu.com/s',
method: 'get',
params: {
arr: JSON.stringify([1])
},
paramsSerializer: (params) => {
let arr = []
for (let key in params) arr.push(key + '=' + encodeURIComponent(params[key]))
return arr.join('&')
},
})
这样输出的url格式就是:
https://www.baidu.com/s?arr=%5B1%5D
这里我们使用了paramsSerializer,其实可以看我的第一张图片,buildURL的第三个入参就是paramsSerializer,也就是如果外界传入了paramsSerializer,那么_encode就是paramsSerializer,如果没传_encode就是内置的encode。
axios({
url: 'https://www.baidu.com/s?' + qs.stringify({ arr: JSON.stringify([1]) }),
method: 'get',
})
这样输出的格式也是
https://www.baidu.com/s?arr=%5B1%5D
URLSearchParams
const params = new URLSearchParams();
params.append('arr', JSON.stringify([1]));
axios({
url: 'https://www.baidu.com/s',
params,
method: 'get',
})
也可以参考官网看一下axios