axios 是 JSON 响应优先的

本文是"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
    }
  }
}
  1. 首先,明确告知服务器,我能接受 JSON 数据响应。
  2. 其次,不发送 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 格式返回响应数据。因此,这种默认设置也减少了一些样板代码的编写,提升了开发体验。

相关推荐
小白学习日记34 分钟前
【复习】HTML常用标签<table>
前端·html
john_hjy37 分钟前
11. 异步编程
运维·服务器·javascript
风清扬_jd1 小时前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
丁总学Java1 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele1 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
It'sMyGo1 小时前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
懒羊羊大王呀1 小时前
CSS——属性值计算
前端·css
xgq2 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
李是啥也不会2 小时前
数组的概念
javascript
用户3157476081352 小时前
前端之路-了解原型和原型链
前端