服务端接收不到axios发送的post请求

接收一个axios发送的post请求,结果数据死活接收不到,请求头也正常,请求头设置Content-type也同样不好使,下面详细分析下问题出在哪儿了。

问题场景

代码很简单,跟示例一样。

1
2
3
4
5
6
7
8
9
10
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

后端使用php接收,get没问题,post一直为空。

问题原因

我们从请求头中可以看出, Content-Type 变成了 application/json;charset=utf-8
然后,因为我们的参数是 JSON 对象,axios 帮我们做了一个 stringify 的处理。
而且查阅 axios 文档可以知道:axios 使用 post 发送数据时,默认是直接把 json 放到请求体中提交到后端的。

那么,这就与我们服务端要求的 'Content-Type': 'application/x-www-form-urlencoded' 以及 @RequestParam 不符合。

解决方案

URLSearchParams传递参数

1
2
3
4
5
6
7
8
9
10
let data = new URLSearchParams()
data.append('firstName': 'Fred')
data.append('lastName': 'Flintstone')
axios.post('/user', data)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

需要注意的是: URLSearchParams 不支持所有的浏览器,但是总体的支持情况还是 OK 的,所以优先推荐这种简单直接的解决方案

qs库

网上有很多方案说使用
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
或者
{headers:{'Content-Type':'application/x-www-form-urlencoded'}}
我试了一下,其实这样还是不行的
【还需要额外的操作,(我们要将参数转换为query参数)】
引入 qs ,这个库是 axios 里面包含的,不需要再下载了。

1
2
3
4
5
6
7
8
9
10
import Qs from 'qs'

let data = {'firstName': 'Fred','lastName': 'Flintstone'}
axios.post('/user', Qs.stringify(data))
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

使用transformRequest

既然 axios 源码中有那么一段【很关键】的代码,那么,我们也可以通过修改 transformRequest 来达到我们的目的。

在 axios 的请求配置项中,是有 transformRequest 的配置的:

1
2
3
4
5
6
7
8
9
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
// 对 data 进行任意转换处理

return data;
}],

OK,那么现在我们的请求就可以写成下面这个样子了:

1
2
3
4
5
6
7
8
9
10
11
import Qs from 'qs'
let data = {firstName: 'Fred',lastName: 'Flintstone'}
axios({
url: '/user',
method: 'post',
transformRequest: [function (data) {
// 对 data 进行任意转换处理
return Qs.stringify(data)
}],
data: data
})

重写axios

【重写一个 axios 实例,重新实现属于我们自己的 transformRequest】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import axios from 'axios'
let instance = axios.create({
transformRequest: [function transformRequest(data, headers) {
normalizeHeaderName(headers, 'Content-Type');
if (utils.isFormData(data) ||
utils.isArrayBuffer(data) ||
utils.isBuffer(data) ||
utils.isStream(data) ||
utils.isFile(data) ||
utils.isBlob(data)
) {
return data;
}
if (utils.isArrayBufferView(data)) {
return data.buffer;
}
if (utils.isURLSearchParams(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
return data.toString();
}
/*改了这里*/
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
let _data = Object.keys(data)
return encodeURI(_data.map(name => `${name}=${data[name]}`).join('&'));
}
return data;
}],
})

类似get传参

1
axios.post('/user',"firstName='Fred'&lastName='Flintstone'");