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

相关推荐
月明长歌2 分钟前
Selenium中隐式等待(Implicit Wait)和显式等待(Explicit Wait)的区别
前端·javascript·selenium
姜太小白4 分钟前
【前端】JavaScript字符串执行方法总结
开发语言·前端·javascript
GIS之路11 分钟前
GDAL 实现影像合并
前端·python·信息可视化
心易行者21 分钟前
Claude Code + Chrome:浏览器层面的AI编程新范式已至
前端·chrome·ai编程
半兽先生23 分钟前
解决使用jsPDF实现表格数据导出pdf功能时中文乱码问题
前端·vue.js·elementui
qq_4061761441 分钟前
吃透JS异步编程:从回调地狱到Promise/Async-Await全解析
服务器·开发语言·前端·javascript·php
幻云201044 分钟前
Python深度学习:筑基与实践
前端·javascript·vue.js·人工智能·python
@大迁世界1 小时前
停止使用 innerHTML:3 种安全渲染 HTML 的替代方案
开发语言·前端·javascript·安全·html
缘木之鱼1 小时前
CTFshow __Web应用安全与防护 第二章
前端·安全·渗透·ctf·ctfshow
沛沛老爹1 小时前
从Web到AI:多模态Agent Skills生态系统实战(Java+Vue构建跨模态智能体)
java·前端·vue.js·人工智能·rag·企业转型