在这篇内容,我将拆解 Axios 的整个流程,从发送请求到接收响应数据。整个过程拆成了一条完整的链路,方便大家理解每一步都在干什么。
一、发起请求的两种方式
整个过程的第一步,就是用户通过 Axios 发起一个请求。这里有两种方式:
不管你用的是哪种方式,最终都会走到同一个地方——createInstance 这个工厂方法。

二、createInstance 工厂方法
当我们调用 createInstance 的时候,它会去读取我们传入的 config 配置信息。
在这个过程中,如果你传入了新的配置,比如自定义了 baseURL,那么工厂方法就会把这些新配置和默认配置进行合并覆盖。(第10行)

处理完配置之后,工厂方法就会去调用 Axios.prototype 上的 request 方法——也就是真正干活的那个方法。
三、request 方法与请求链
调用 request 方法之后,整个请求就进入了核心处理阶段。request 方法的作用是什么呢?它的核心功能就是串联整个请求链——把请求拦截器、响应拦截器、还有真正的网络请求(dispatchRequest)按顺序串起来。
它具体是怎么做的呢?它内部有一个数组叫 chain,也就是请求链。request 方法会按照顺序把请求拦截器插入到这个链当中,然后再把 dispatchRequest 也放进去。
如果你有设置请求拦截器或者响应拦截器的话,它就会在这一步做相应的处理。
四、请求拦截器
在请求真正发出去之前,会先进入请求拦截器。
在请求拦截器里面,我们可能会做这些事情:
- 把请求头设置得更完整
- 对请求的数据做一些预处理
- 比如添加 token、修改 content-type 等等


这一步的目的,就是在请求发出之前,对请求做最后的“加工”。
注意: 如果添加了多个请求拦截器,它们的执行顺序是后添加的先执行。在request方法构建 chain 数组的时候,会从后往前遍历请求拦截器列表,将每对 [fulfilled, rejected] 用unshift插入到 chain 的头部,所以后添加的请求拦截器会先执行。(也就是三所提到的过程)
五、transformRequest —— 数据预处理
请求拦截器处理完之后,进入 dispatchRequest。在 dispatchRequest 内部,会调用transformData()对请求数据进行 transformRequest 转换处理,比如序列化 JSON、设置 Content-Type 等。
这一步主要做的是什么呢?它会对我们传入的数据进行预处理,比如:
- 如果我们传的是一个对象,或者是一个 JSON 格式的数据,或者 URL Encoding 格式的数据,那么它就会在请求头里面设置 content-type,告诉浏览器我们传的是什么格式

- 另外它也可能对数据进行 URL 编码拼接之类的处理
简单来说,就是让请求数据以正确的格式发送给后端。
六、dispatchRequest —— 真正发送请求
数据预处理完成之后,就进入到 dispatchRequest 了。
但是要注意:真正发送请求的并不是 dispatchRequest 本身。
dispatchRequest 的作用是什么呢?它主要是做两件事:
最终合并 headers——把之前设置的各种请求头合并到一起
调用 adapter——这个 adapter 才是真正执行网络请求的函数

七、adapter —— 根据环境选择请求方式
那么 adapter 是怎么发送请求的呢?
在浏览器环境下,它用的是 XMLHttpRequest(也就是 XHR 对象)。在 Node.js 环境下,它会用对应的 HTTP 模块。
它会根据我们运行的环境来选择合适的 adapter:
- 如果是在浏览器里运行,就选 XHR
- 如果是在 Node.js 里运行,就选 Node.js 的 HTTP 模块
当然,我们也可以通过 adapter 字段自己去手动配置,指定用哪一个。如果我们没有手动配置的话,Axios 就会根据运行环境自动选择合适的 adapter。
注意,XMLHttpRequest 本身并不是 Promise,是 Axios 的 adapter 把它封装成了 Promise 返回给我们。
八、请求成功与失败
当 adapter 发送完请求之后,它会返回一个 Promise 对象。
这个 Promise 的成功状态叫 fulfilled,失败状态叫 rejected。
成功的判断标准是什么? 就是返回的 HTTP 状态码必须在 200 到 299 之间,也就是大于等于 200 且小于 300,这个范围才算请求成功。如果不在这个范围之内,那就算失败——可能是网络错误、超时、状态码超出范围等等。

成功之后
如果请求成功了,就会执行 transformResponse,对响应数据进行转换处理。比如把后端返回的 JSON 字符串转换成 JavaScript 对象,方便我们后续使用。
失败之后
如果请求失败了,直接进入 rejected 分支,然后走响应拦截器的 onRejected,或者直接报错。
九、主动取消请求(特别注意)
这里有一个特别需要注意的地方——主动取消请求。
如果我们是主动撤销或者中断一个请求,比如用了 AbortController 来取消请求,那么它会直接进入到 rejected 分支,抛出一个 CancelError 错误。
关键区别来了:
- 被动触发的错误(比如网络错误、超时、状态码不对)→ 会进入响应拦截器的失败回调进行处理
- 主动取消的请求(比如用户手动中断)→ 同样会进入响应拦截器的失败回调,也就是 onRejected 分支,最终抛出一个 CancelError

也就是说,通过CancelToken或 AbortController 主动取消请求时,会进入 adapter 的rejected分支,随后进入响应拦截器的onRejected处理。但如果是在请求拦截器阶段被拒绝,则不会进入响应拦截器。
十、响应拦截器
请求发送完成之后,就会进入响应拦截器。
在响应拦截器里面,我们可以对返回的数据做统一的处理,比如:
-
对响应数据进行格式化
-
统一处理错误码
-
提取真正需要的数据部分

注意: 如果添加了多个响应拦截器,它们的执行顺序是先添加的先执行。在request方法构建chain数组时,会从前往后遍历响应拦截器列表,将每对 [fulfilled, rejected] 用 push 追加到chain的尾部,所以先添加的响应拦截器会先执行。(和请求拦截器相反的过程)
十一、请求链的完整顺序
还记得我们在 request 方法里面说的那个 chain 数组吗?它串联了所有的拦截器和请求流程。
整个请求链的执行顺序是这样的:
也就是说,从用户发起请求,到最后拿到结果,整个流程是:
十二、最终返回给用户
经过响应拦截器的处理后,最终会得到一个 response 对象,里面包含了:
- data —— 实际的数据
- status —— 状态码
- headers —— 响应头
- config —— 请求配置
- 等等
如果出错了,返回的就是 error 对象。

最后这些东西会传递给我们用户代码里的 .then()、.catch() 或者 try…catch,整个请求流程就结束了。
总结
Axios 的整个请求流程可以概括为几个核心节点:
网硕互联帮助中心


评论前必须登录!
注册