Axios 核心特性全解析:同构请求、Fetch 适配器、进度事件与源码级实现细节
【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios
axios 是一个面向浏览器与 Node.js 的同构 HTTP 客户端,官方文档 features.md 系统性地列出了它的核心能力。本文以该文档为骨架,逐条深入每项特性的仓库源码实现——从适配器选择机制、Fetch 适配器的底层原理,到请求体自动序列化、进度事件采集和 XSRF 防护的默认配置,帮助读者不仅知道 axios "能做什么",更清楚它 "为什么能做到"。
一、同构(Isomorphic):一套 API 同时跑在浏览器与 Node.js
features 文档开篇即定义了 axios 的第一个核心定位:Isomorphic——同一个 HTTP 客户端同时支持浏览器和 Node.js,前端代码与后端代码可以使用完全一致的请求 API。这对构建渐进式 Web 应用(PWA)、单页应用(SPA)以及服务端渲染(SSR)应用尤其重要:同一份数据获取逻辑无需在两端各写一遍,团队也无需在xhr、fetch、http模块之间做 API 翻译。
从源码结构看,这种同构性是通过三层机制实现的:
1. 平台抽象层。库的核心入口 lib/platform/index.js 按当前构建环境合并平台能力:
import platform from './node/index.js'; import * as utils from './common/utils.js'; export default { ...utils, ...platform, };默认指向 Node 平台(lib/platform/node/index.js 导出isNode: true及URLSearchParams/FormData/Blob类),而 lib/platform/browser/index.js 则导出isBrowser: true与浏览器侧对应的类实现。两侧协议白名单也略有差异:Node 侧支持['http', 'https', 'file', 'data'],浏览器侧额外包含blob和url。
2. 打包时的模块替换。package.json 中的browser字段告诉打包器在浏览器构建时替换 Node 专属模块:
"browser": { "./lib/adapters/http.js": "./lib/helpers/null.js", "./lib/platform/node/index.js": "./lib/platform/browser/index.js", "./lib/platform/node/classes/Buffer.js": "./lib/helpers/null.js", "./lib/platform/node/classes/FormData.js": "./lib/helpers/null.js" }也就是说,浏览器构建会彻底剔除 Node 的http适配器与Buffer依赖,避免把不需要的代码打进前端包。exports字段进一步区分了入口:bun、react-native、browser、default各自指向不同的产物(dist/browser/axios.cjs、dist/node/axios.cjs或源码index.js),保证每种运行时拿到最合适的构建。
3. 默认配置共享。无论运行在哪一端,请求都经过同一份默认配置 lib/defaults/index.js,其中env字段会把当前平台的FormData、Blob类注入进去:
env: { FormData: platform.classes.FormData, Blob: platform.classes.Blob, },这正是 features 文档中"Compatible with spec-compliant FormData and Blob (including node.js)"一条的落点:Node 环境下的FormData来自 lib/platform/node/classes/FormData.js,而序列化行为与浏览器规范保持一致。
二、Fetch 适配器:可选的第一等公民
features 文档将Fetch support标记为新增特性(New):axios 提供对 Fetch API 的一级支持,且该适配器是可选的、通过配置启用;XHR 与 Fetch 两种适配器对外保持完全一致的 API,因此可以在不改动现有代码的前提下平滑迁移到 Fetch。
默认适配器优先级。默认配置中已声明了三者的回退顺序(lib/defaults/index.js):
adapter: ['xhr', 'http', 'fetch'],选择逻辑。具体的解析算法在 lib/adapters/adapters.js 的getAdapter函数中:
- 注册表
knownAdapters只包含三个已知适配器:http(Node.js)、xhr(浏览器)、fetch(基于 Fetch API 的请求)。其中fetch注册为一个懒加载对象{ get: fetchAdapter.getFetch },因为是否可用取决于运行时环境; - 函数按数组顺序逐个尝试,名称会被
toLowerCase()后查表,未知名称直接抛出Unknown adapter '<name>'错误; fetch适配器的get(config)会做环境探测(fetch是否为函数、Request/Response是否可用),不支持时返回false,getAdapter便继续尝试下一个;- 若全部失败,抛出的
AxiosError会附带逐条失败原因——例如adapter xhr is not supported by the environment或adapter http is not available in the build(浏览器构建中http被替换为 null 后即为后者),这对排查"为什么我的请求没走预期适配器"非常有帮助。
Fetch 适配器实现。lib/adapters/fetch.js 是完整的独立实现,其factory(env)工厂函数会:
- 探测
fetch、Request、Response、ReadableStream、TextEncoder等全局能力的可用性,任一关键能力缺失即返回false(从而让getAdapter回退到下一适配器); - 提供一组贴近浏览器语义的默认请求选项:
const DEFAULT_REQUEST_OPTIONS = { cache: 'default', redirect: 'follow', referrer: 'about:client', referrerPolicy: '', mode: 'cors', integrity: '', keepalive: false, priority: 'auto', window: null, };- 复用与 xhr/http 适配器相同的基础设施——
composeSignals合成多个 AbortSignal、progressEventDecorator采集上传进度、settle统一结算响应(见 lib/core/settle.js)、trackStream追踪响应流的消费状态。
正因三条路径共用同一套 settle/进度/取消管线,features 文档所说"the same API is maintained for both the XHR and Fetch adapters"在代码层面是成立的:切换adapter: 'fetch'只是换掉传输层,拦截器、超时、进度、取消等行为不变。仓库中也有对应的单元与冒烟测试,如 tests/unit/adapters/fetch.test.js、tests/smoke/cjs/tests/fetch.smoke.test.cjs 和 tests/smoke/bun/tests/fetch.smoke.test.ts。
三、运行时支持范围:浏览器、Node.js、Bun 与 Deno
features 文档对运行时的承诺是:
- 浏览器:支持所有现代浏览器及若干旧版浏览器,包括 Chrome、Firefox、Safari 和 Edge,适合需要覆盖较宽浏览器矩阵的 Web 应用;
- Node.js:广泛兼容多个 Node.js 版本,官方测试兼容性可回溯到v12.x,适合无法(或不方便)升级到最新 Node.js 版本的环境;
- Bun 与 Deno:仓库内置了
tests/smoke/bun与tests/smoke/deno两套冒烟测试,验证关键运行时行为、提升跨运行时兼容的信心。
从仓库实际内容可以确认这一点:
- tests/smoke/bun/tests/ 下覆盖 cancel、error、fetch、formData、headers、http、import、interceptors、progress、timeout 等场景,通过
bun test执行(对应 package.json 的test:smoke:bun脚本); - tests/smoke/deno/tests/ 覆盖 cancel、error、fetch、headers、import 等场景,通过
deno task test执行(test:smoke:deno脚本); - 除此之外还有 tests/smoke/cjs/ 与 tests/smoke/esm/ 两套针对 CommonJS/ESM 双模块形态的冒烟测试,说明同构承诺不仅针对"浏览器 vs Node",也针对不同的模块体系。
浏览器侧的适配能力则由 tests/browser/ 下的 Playwright 驱动浏览器测试(xhr 行为、cookies、CORS 相关的isURLSameOrigin、进度事件等)持续验证。
四、其余特性逐项对应到源码
features 文档的 "Additional features" 列出了 13 项能力,下面逐一给出仓库中的实现位置,并补充关键默认值。
1. Promise API 与请求生命周期
axios 的请求/响应链路完全建立在 Promise 之上。核心类 lib/core/Axios.js 负责实例创建与方法分发,lib/core/dispatchRequest.js 在发送前依次执行transformRequest、拦截器,再由适配器返回的 Promise 进入settle结算,成功/失败最终统一为AxiosError(lib/core/AxiosError.js)。入口文件 index.js 同时以命名导出暴露Axios、AxiosError、CanceledError、isAxiosError等,方便类型系统(见 index.d.ts)精确感知每个 API。
2. 请求与响应拦截器
lib/core/InterceptorManager.js 管理两个拦截器队列(请求拦截器 / 响应拦截器),use()注册、eject()移除。相关行为由 tests/unit/core/InterceptorManager.test.js 和 tests/browser/interceptors.browser.test.js 等测试覆盖。
3. 请求/响应数据转换(transform)
lib/core/transformData.js 负责在请求前与响应后串接执行转换器;转换器本身定义在默认配置中(lib/defaults/index.js),这也是"自动请求体序列化"和"响应自动 JSON 处理"两条特性的共同实现。
4. Abort Controller 与超时
默认配置timeout: 0表示不启用超时(lib/defaults/index.js)。取消能力由 lib/cancel/CanceledError.js、lib/cancel/isCancel.js 与 lib/cancel/CancelToken.js 提供;多个信号(如用户传入的AbortSignal与超时信号)的合并逻辑在 lib/helpers/composeSignals.js 中完成,三个适配器都调用它来统一"任一信号触发即中止请求"的语义。示例可参考 examples/abort-controller/ 目录。
5. 查询参数序列化(支持嵌套)
params的拼接由 lib/helpers/buildURL.js 完成,可配合paramsSerializer自定义格式;URL 编码表单的构建复用 lib/helpers/toURLEncodedForm.js 与 lib/helpers/AxiosURLSearchParams.js,其中对嵌套对象/数组条目的扁平化序列化是"support for nested entries"的具体实现,测试见 tests/unit/helpers/AxiosURLSearchParams.test.js 与 tests/unit/axios.test.js。
6. 请求体自动序列化:JSON / multipart / urlencoded / HTML 表单
默认transformRequest(lib/defaults/index.js)按内容类型与数据类型分派,逻辑顺序是:
- HTML 表单元素(
utils.isHTMLForm(data))→ 自动包成FormData,即 features 文档所说的 "Posting HTML forms as JSON"(配合 JSON 内容类型时进一步序列化为 JSON 对象,见第 8 节的formDataToJSON路径); - FormData→ 原样发送(若显式声明了
application/json则经 lib/helpers/formDataToJSON.js 转成 JSON 字符串); - ArrayBuffer / Buffer / Stream / File / Blob / ReadableStream→ 原样透传(二进制与流式上传不受干扰);
- ArrayBufferView→ 取其底层
buffer; - URLSearchParams→ 设置
Content-Type: application/x-www-form-urlencoded;charset=utf-8并toString(); - 普通对象→ 按内容类型分派:
application/x-www-form-urlencoded走 lib/helpers/toURLEncodedForm.js;文件列表或multipart/form-data走 lib/helpers/toFormData.js(支持formSerializer自定义序列化,且使用当前平台的FormData类); - 兜底:对象或声明了 JSON 内容类型时,自动设置
Content-Type: application/json并用stringifySafely(能安全处理"已是合法 JSON 字符串"的输入)序列化。
这与 features 文档列出的三种自动序列化目标(application/json、multipart/form-data、application/x-www-form-urlencoded)一一对应。相关测试见 tests/unit/axios.test.js 和 tests/unit/toFormData.test.js。
7. 响应自动 JSON 处理
默认transformResponse(lib/defaults/index.js)在responseType === 'json'(或开启transitional.forcedJSONParsing)时尝试JSON.parse:
- 解析失败且
responseType显式为json时,会包装为AxiosError.ERR_BAD_RESPONSE抛出(严格模式); - 若
transitional.silentJSONParsing为真则静默降级、保留原始字符串。
注意Response对象与ReadableStream会直接透传不做解析——这正对应 Fetch 适配器下的流式响应场景。
8. 进度事件:速度、剩余时间
features 文档特别提到进度事件在浏览器和 Node.js 中都可用,且附带额外信息(速度、剩余时间)。实现链条为:
- lib/helpers/progressEventReducer.js 提供
progressEventReducer/progressEventDecorator,把下载/上传的字节数变化包装成进度回调; - lib/helpers/speedometer.js 维护单位时间吞吐量样本,据此推算速率与预计剩余时间——这是"extra info (speed rate, remaining time)"的来源;
- 三个适配器统一接入:xhr 适配器监听
upload/download进度事件,http 适配器读取流字节,fetch 适配器则基于分块(默认 64KB,见 lib/adapters/fetch.js 的DEFAULT_CHUNK_SIZE)统计。
测试可参考 tests/browser/progress.browser.test.js、tests/smoke/cjs/tests/progress.smoke.test.cjs 及 tests/unit/helpers/progressEventReducer.test.js。
9. Node.js 带宽限制
features 文档中的 "Setting bandwidth limits for node.js" 指 http 适配器提供的rateLimit配置,对请求体/响应流进行节流,官方详解见 docs/pages/advanced/rate-limiting.md,冒烟测试为 tests/smoke/cjs/tests/rateLimit.smoke.test.cjs。开发环境可依赖stream-throttle(见 package.json devDependencies)在本地模拟限速链路进行验证。
10. FormData / Blob 规范兼容性
如第一节所述,两端分别使用 lib/platform/node/classes/ 与 lib/platform/browser/classes/ 下的FormData、Blob、URLSearchParams实现,并通过默认配置的env字段暴露给toFormData等辅助函数,从而保证 Node 端构造的 FormData 与浏览器规范语义一致(含文件项、嵌套项处理)。
11. XSRF 客户端防护
features 文档的最后一项 "Client side support for protecting against XSRF" 在默认配置中有明确默认值(lib/defaults/index.js):
xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN',即浏览器端在跨域请求(withCredentials)时,自动从 CookieXSRF-TOKEN读取值并写入请求头X-XSRF-TOKEN。配套辅助实现为 lib/helpers/cookies.js 与同源判定 lib/helpers/isURLSameOrigin.js,测试见 tests/browser/xsrf.browser.test.js。
五、依赖面与构建产物
features 文档承诺的跨端能力,对应着刻意保持精简的运行时依赖(package.json):仅follow-redirects(Node 端重定向)、form-data(Node 端 multipart)、https-proxy-agent与proxy-from-env(代理支持)四个依赖。
构建侧由 rollup.config.js 与 gulpfile.js 产出dist/esm、dist/browser、dist/node多形态产物,exports字段再按bun/react-native/browser/ 默认条件分发,配合browser字段的模块替换,共同支撑起"一份 API、多种运行时"的特性承诺。
小结
| 特性(features 文档原文要点) | 仓库中的落点 |
|---|---|
| 同构(浏览器 + Node.js) | lib/platform/ 平台层 + package.json 的browser/exports模块替换 |
| Fetch 支持(可选、API 一致) | 默认adapter: ['xhr', 'http', 'fetch'](lib/defaults/index.js)、lib/adapters/adapters.js 选择逻辑、lib/adapters/fetch.js |
| 宽浏览器与 Node v12.x+ 支持 | tests/browser/、tests/smoke/cjs/ |
| Bun / Deno 冒烟测试 | tests/smoke/bun/、tests/smoke/deno/ |
| 自动序列化 JSON / multipart / urlencoded、HTML 表单 | lib/defaults/index.js 的transformRequest |
| 响应自动 JSON 解析 | lib/defaults/index.js 的transformResponse |
| 进度事件(速度、剩余时间) | lib/helpers/progressEventReducer.js、lib/helpers/speedometer.js |
| Node.js 带宽限制 | docs/pages/advanced/rate-limiting.md |
| 规范级 FormData/Blob(含 Node) | lib/platform/node/classes/、lib/platform/browser/classes/ |
| XSRF 防护 | xsrfCookieName/xsrfHeaderName默认值(lib/defaults/index.js) |
读到这里,你应该已经能回答两个问题:axios 的"跨端一致 API"是靠平台抽象、打包期模块替换与统一 settle 管线三者共同实现的;而 Fetch 适配器等新能力则是以"可选回退 + 环境探测"的方式嵌入既有适配器框架的——理解了这两点,再去看仓库中任意一个适配器或辅助模块,都能快速定位它在特性大图里的位置。
【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考