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 格式返回响应数据。因此,这种默认设置也减少了一些样板代码的编写,提升了开发体验。

相关推荐
我叫张小白。1 小时前
Vue3监视系统全解析
前端·javascript·vue.js·前端框架·vue3
WYiQIU5 小时前
11月面了7.8家前端岗,兄弟们12月我先躺为敬...
前端·vue.js·react.js·面试·前端框架·飞书
谢尔登5 小时前
简单聊聊webpack摇树的原理
运维·前端·webpack
娃哈哈哈哈呀6 小时前
formData 传参 如何传数组
前端·javascript·vue.js
zhu_zhu_xia7 小时前
vue3+vite打包出现内存溢出问题
前端·vue
tsumikistep7 小时前
【前后端】接口文档与导入
前端·后端·python·硬件架构
行走的陀螺仪7 小时前
.vscode 文件夹配置详解
前端·ide·vscode·编辑器·开发实践
2503_928411568 小时前
11.24 Vue-组件2
前端·javascript·vue.js
Bigger8 小时前
🎨 用一次就爱上的图标定制体验:CustomIcons 实战
前端·react.js·icon
谢尔登8 小时前
原来Webpack在大厂中这样进行性能优化!
前端·webpack·性能优化