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

相关推荐
余道各努力,千里自同风12 分钟前
小程序中获取元素节点
前端·小程序
PineappleCoder14 分钟前
大模型也栽跟头的 Promise 题!来挑战一下?
前端·面试·promise
非凡ghost15 分钟前
MousePlus(鼠标增强工具) 中文绿色版
前端·windows·计算机外设·软件需求
Moonbit29 分钟前
MoonBit Pearls Vol.13:初探 MoonBit 中的 JavaScript 交互
javascript·后端
焚 城30 分钟前
EXCEL(带图)转html【uni版】
前端·html·excel
我家媳妇儿萌哒哒34 分钟前
Vue2 elementUI年份区间选择组件
前端·javascript·elementui
山塘小鱼儿39 分钟前
JavaScript 性能优化实战大纲
javascript
笨笨狗吞噬者40 分钟前
【uniapp】小程序体积优化,分包异步化
前端·微信小程序·uni-app
该用户已不存在41 分钟前
Golang 上传文件到 MinIO?别瞎折腾了,这 5 个库拿去用
前端·后端·go
snows_l1 小时前
JavaScript 性能优化实战大纲
前端