本文是"axios源码系列"第二篇。上文我们介绍了 axios 中是如何实现取消请求 的,本文我将介绍另一个话题:axios 是 JSON 响应优先的。
那为什么这么说呢?我们能从 2 个方面的表现进行阐述。
表现一:默认请求头
你可能没有注意到,每个 axios 请求默认会有 2 个请求头配置,位于 lib/defaults/index.js。
js
// /v1.6.8/lib/defaults/index.js#L144
const defaults = {
// ...
headers: {
common: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': undefined
}
}
}
- 首先,明确告知服务器,我能接受 JSON 数据响应。
- 其次,不发送 Content-Type 头信息。
这块配置会在请求发出前,与用户传入的 config.headers 进行合并。
js
// /v1.6.8/lib/core/Axios.js#L72
config = mergeConfig(this.defaults, config);
接着扁平化,将 config.headers 处理成 AxiosHeaders 实例对象。
js
// /v1.6.8/lib/core/Axios.js#L100-L113
// Flatten headers
let contextHeaders = headers && utils.merge(
headers.common,
headers[config.method]
);
headers && utils.forEach(
['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
(method) => {
delete headers[method];
}
);
config.headers = AxiosHeaders.concat(contextHeaders, headers);
AxiosHeaders 类似于标准 Headers API,提供了各种操作头信息的方法,比如 get()、set()、concat() 等。
看下最终请求头效果。
这就是 axios 是 JSON 响应优先的第一个表现。
表现二:响应数据处理
不过重要的还是第二个表现,即在处理响应数据的时候。
我们都知道,我们可以为 axios 请求指定 responseType 配置项。以下面代码为例:
js
axios.get('https://httpstat.us/200', {
responseType: 'json'
})
.then(res => {
console.log(res)
// { data: {code: 200, description: 'OK'} }
})
这里我们告知 axios,响应数据是 JSON 格式的,需要处理成 JSON 对象给我们。
但这个配置项是可选的,因为 axios 默认就会把响应数据看做 JSON 格式处理。
这块逻辑跟另一个配置项 transformResponse 有关。
如果你没有自定义 transformResponse 这个配置项,那么它的默认逻辑如下。
js
// /blob/v1.6.8/lib/defaults/index.js#L99
const defaults = {
// ...
transformResponse: [function transformResponse(data) {
const JSONRequested = this.responseType === 'json';
if (
typeof data === 'string' &&
(!this.responseType || JSONRequested)
) {
try {
return JSON.parse(data);
} catch (e) {}
}
return data;
}],
// ...
}
transformResponse 配置项接收请求返回的响应数据 data,决定最终返回的数据类型。而 data 的来源如下(以浏览器端实现为例)。
js
// /v1.6.8/lib/adapters/xhr.js#L100
const responseData = !responseType || responseType === 'text' || responseType === 'json'
? request.responseText
: request.response;
这里的 responseType,是从传入用户的 config 里获取的。
js
// /v1.6.8/lib/adapters/xhr.js#L52
let {responseType, withXSRFToken} = config;
观察就能知道:当传入的 config 没有包含 responseType,或 responseType 值为 'text' 或 'json' 时,data 即 request.responseText,也就是一个字符串。
回到刚才的逻辑。
js
transformResponse: [function transformResponse(data) {
const JSONRequested = this.responseType === 'json';
if (
typeof data === 'string' &&
(!this.responseType || JSONRequested)
) {
try {
return JSON.parse(data);
} catch (e) {}
}
return data;
}],
如果 responseType 没有设置,或者 responseType 被设置成 'json'。那么就以 JSON.parse(data) 方式处理并返回。
看,这里的 data 属性就是一个 JS 对象了。
如果把 responseType 被设置成 'text',返回的就是没经过任何处理的字符串了。
js
axios.get('https://httpstat.us/200', {
responseType: 'text'
})
效果如下。
这就是 axios 是 JSON 响应优先的第二个表现,也是直接原因。
总结
本文带大家了解了 axios 的另一个特性,它是 JSON 响应优先的。也就是说,JSON 响应在 axios 中是"一等公民"。
这并不难理解,因为目前几乎所有前端项目都在使用 JSON 格式返回响应数据。因此,这种默认设置也减少了一些样板代码的编写,提升了开发体验。