首页
/ Axios 升级指南:v0.x 到 v1.19.0 破坏性变更的源码级解读

Axios 升级指南:v0.x 到 v1.19.0 破坏性变更的源码级解读

2026-09-04 19:41:43作者:何举烈Damon

本文基于 Axios 官方升级文档(docs/es/pages/getting-started/upgrade-guide.md),系统梳理从 v0.x 升级到 v1.x、以及升级到当前 v1.19.0 版本时的全部关键破坏性变更:导入方式、拦截器类型、请求头结构、multipart 表单、参数序列化与内部 API 收敛。文中每一项变更均结合当前仓库源码(lib/ 目录)给出实现层面的证据,帮助你安全、可验证地完成版本迁移。

升级总原则与版本背景

官方建议:从哪个主版本开始迁移,就要逐条阅读经过的每个主版本的发布说明(release notes),因为它们可能包含本指南未覆盖的破坏性变更信息。

可以确认当前仓库的 package.json 中版本号为 1.19.0,因此“升级到 v1.19.0”一节描述的就是当前源码中的最新行为。仓库根目录另有 MIGRATION_GUIDE.md,提供了 0.x 到 1.x 错误处理策略、迁移分阶段流程和常见排障模式等补充材料,可与本指南对照阅读。

升级到 v1.19.0

畸形 HTTP(S) URL 将被直接拒绝

v1.19.0 开始,请求会拒绝协议后缺少 //http: / https: 形式 urlbaseURL。例如 https:example.comhttps:/example.com 都会被判定为畸形地址,请替换为 https://example.com 这类规范写法。

产生的 AxiosError 使用错误码 ERR_INVALID_URL,并且错误消息中会安全地标识出出错的 URL,同时隐藏其中的敏感信息(凭据、查询参数值、fragment 内容)。这是一个有意为之的安全变更:防止畸形 URL 的规范化过程被利用来绕过 baseURL 约束或 URL 白名单校验。

源码层面的实现证据:

  • 判定逻辑位于 lib/core/buildFullPath.js#L8-L56:正则 /^https?:(?!\/\/)/i 匹配“协议后不跟随 //”的字符串;assertValidHttpProtocolURLbuildFullPath 入口处分别对 requestedURLbaseURL 做断言,命中即抛出携带 AxiosError.ERR_INVALID_URL 的错误(lib/core/AxiosError.js#L216 定义了该错误码常量)。
  • 错误消息脱敏由同一文件中的 redactSensitiveURLParts 完成(lib/core/buildFullPath.js#L10-L43):把 userinfo(user:pass@)、查询参数值、fragment 内容替换为 REDACTED 标记,同时保留 scheme、host、path 和参数名,使出错请求仍可准确定位。之所以在错误消息里做脱敏,是因为 AxiosErrormessage 会被原样记录进日志,而基于 config.redact 的脱敏模型无法覆盖到消息文本。
  • buildFullPath 是完整 URL 拼装的唯一入口:lib/core/Axios.jsgetUri 中调用它,请求分发路径同样经由它组合 baseURLurl,因此该断言对两种 URL 来源都生效。

同步请求拦截器抛出错误的新行为

同步请求拦截器(synchronous request interceptor)抛出错误时,Axios 的处理规则为:

  1. 立即调用该拦截器配对的拒绝处理器(rejection handler),并停止执行剩余请求拦截器
  2. 如果拒绝处理器正常返回(没有抛出、也没有返回被拒绝的 Promise),错误即被视为“已处理”,Axios 会用最后一个合法配置继续发送请求——注意:拒绝处理器的返回值不会成为新的请求配置;
  3. 如果你的校验逻辑必须阻止请求发送,请不注册拒绝处理器,或者在拒绝处理器中抛出异常 / 返回一个被拒绝的 Promise;
  4. 终止性错误(terminal errors)会继续流向响应拒绝拦截器(response rejection interceptors)。

该行为可以直接在同步拦截器链的实现中得到印证,见 lib/core/Axios.js#L211-L240

try {
  newConfig = onFulfilled ? onFulfilled(newConfig) : newConfig;
} catch (error) {
  if (!onRejected) {
    promise = Promise.reject(error);  // 无拒绝处理器:直接失败
    break;
  }
  try {
    const rejectedResult = onRejected.call(this, error);
    if (utils.isThenable(rejectedResult)) {
      promise = Promise.resolve(rejectedResult).then(() =>
        dispatchRequest.call(this, newConfig)  // 注意:用的是 newConfig(最后一个合法配置)
      );
    }
  } catch (rejectedError) {
    promise = Promise.reject(rejectedError);
  }
  break;  // 停止剩余请求拦截器
}

可以看到:拒绝处理器正常返回时,后续 dispatchRequest 接收的是循环中尚未被覆盖的 newConfig,即“最后一个有效配置”,其返回值并未参与配置替换;随后 break 保证剩余请求拦截器不再执行。

从 v0.x 升级到 v1.x

导入声明改为 default 导出

v1.x 中 Axios 的入口模块改为仅保留 default 导出,你需要把具名导入 import { axios } from "axios" 改为默认导入:

- import { axios } from "axios";
+ import axios from "axios";

源码证据:

  • lib/axios.js#L86-L89axios.default = axios; 之后 export default axios;,注释明确写着 “this module should only have a default export”。
  • 包入口 index.js 负责“解包”:它 import axios from './lib/axios.js' 后,再把这个默认实例上的静态属性(createAxiosAxiosErrorCanceledErrorisCancelCancelTokenVERSIONallCancelisAxiosErrorspreadtoFormDataAxiosHeadersHttpStatusCodeformToJSONgetAdaptermergeConfig)重新以具名方式导出,从而在 ESM 与 CJS 下保持一致的顶层导出面。也就是说,公共 API 依然存在,但获取核心实例必须走 default 导出。

拦截器系统:请求拦截器参数类型变化

在 v1.x 中,请求拦截器的 config 参数类型从公开的 AxiosRequestConfig 变为 InternalAxiosRequestConfig(该类型定义在 index.d.ts 中),你需要按新类型标注参数:

- axios.interceptors.request.use((config: AxiosRequestConfig) => {
+ axios.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    return config;
  });

原因是拦截器拿到的已经是完成 headers 扁平化、method 解析等内部加工后的“内部配置”对象,与对外承诺的公开 AxiosRequestConfig 形状并不相同(例如其中 headers 已是 AxiosHeaders 实例)。这一区别也体现在 lib/core/Axios.js 的请求管线中:拦截器链在 mergeConfig 与 headers 归一化(第 92 行、第 164 行)之后才执行。

请求头结构:移除 common 属性

v1.x 移除了请求头中的 common 层级属性,代码需要相应更新:

- if (request.headers?.common?.Authorization) {
-       request.headers.common.Authorization = ...
+ if (request.headers?.Authorization) {
+       request.headers.Authorization = ...

原先放在 commongetpost 等键下的默认头,现在直接定义在 axios.defaults.headers 上:

- axios.defaults.headers.common["Accept"] = "application/json";
+ axios.defaults.headers["Accept"] = "application/json";

从源码结构看,这个“移除”是发生在请求构造阶段的:lib/core/Axios.js#L153-L164 中,headers.commonheaders[config.method] 先被合并为 contextHeaders,随后遍历 ['delete', 'get', 'head', 'post', 'put', 'patch', 'query', 'common'] 删除这些方法级键,最后经 AxiosHeaders.concat 生成扁平化的 config.headers。因此拦截器与后续管线里看到的请求头已经是无 common 层级的扁平结构。

multipart 表单数据自动处理

当请求携带 FormData 负载时,Content-Type: multipart/form-data(含 boundary)现在会自动设置,请删除任何手动设置的该请求头,避免产生重复头:

- axios.post("/upload", formData, {
-   headers: { "Content-Type": "multipart/form-data" },
- });
+ axios.post("/upload", formData);

实现上,FormData 的边界头由其实现自身生成,再经由 lib/core/setFormDataHeaders.js 合并进请求头(默认策略合并全部 FormData 头;策略为 content-only 时仅复制 content-type/content-length,见该文件 第 16-27 行)。此外,如果你显式设置 Content-Type: application/json,Axios 现在会自动将请求数据序列化为 JSON,无需再手写 JSON.stringify

参数序列化(params)的破坏性变更

v1.x 对 URL 参数序列化引入了多处破坏性变更,最重要的是:

1. params 默认采用百分号编码(percent-encoded)。 如果你的后端期望 qs 风格的裸方括号编码,需要配置自定义序列化器:

import qs from 'qs';

axios.create({
  paramsSerializer: {
    serialize: (params) => qs.stringify(params, { arrayFormat: 'brackets' }),
  },
});

2. params 中的嵌套对象默认使用方括号记法foo[bar]=1),而不再是点记法(foo.bar=1)。若后端期望点记法,请使用自定义序列化器。

3. nullundefined 的处理变得一致null 值被序列化为空字符串,undefined 值则被完全忽略、不出现在查询串中。

源码证据:

  • 序列化入口在 lib/helpers/buildURL.js#L31-L57:若传入 paramsSerializer.serialize 函数则完全交给自定义逻辑;否则走内置的 lib/helpers/AxiosURLSearchParams.js,其 toString 默认对每个键值做百分号编码(encodeURIComponent 为基础,并对 !'()~、空格做了 RFC 友好的替换,见 第 13-25 行)。
  • 方括号记法与 null/undefined 的语义实现在 lib/helpers/toFormData.jsAxiosURLSearchParams 通过 toFormData(params, this, options) 遍历参数树;数组元素键默认渲染为 key[]第 213-224 行),convertValuenull 转为空字符串(第 121-122 行),而 undefined/null 的顶层与数组项在遍历时被直接跳过(第 216 行、第 259 行)。toFormData 同时暴露了 dots 选项,这是恢复“点记法”行为的底层开关(默认 false 即方括号)。
  • 完整的 paramsSerializer 配置选项说明可参阅 请求配置 文档页。

内部实现不再导出

v1.x 起,Axios 决定不再导出内部实现,代码应只使用公共 API。这一收敛的动机是简化 API、缩小暴露面,使得后续版本可以修改内部实现而无需将其声明为破坏性变更。

这一点可以从包入口的导出清单直接验证:index.js#L26-L45 只导出 axios(default)、createAxiosAxiosErrorCanceledErrorisCancelCancelTokenVERSIONallCancelisAxiosErrorspreadtoFormDataAxiosHeadersHttpStatusCodeformToJSONgetAdaptermergeConfig 等公共成员;v0.x 时代可被 require('axios/lib/...') 或具名访问的 dispatchRequestbuildURLmergeConfig 之外的内部模块等,均不在公开面中。如果你此前依赖了内部模块,请在 API 参考 中确认对应公共替代方案。

请求配置对象的其他变化

v1.x 还对请求配置对象(request config)做了调整(新增与移除的配置项、默认值变化等),完整、最新的配置说明请以 请求配置 参考页为准。

本指南未覆盖的破坏性变更

官方声明本指南不是穷尽的,可能未覆盖所有破坏性变更。如果你在升级中遇到指南未提及的问题,请在 Axios 官方文档仓库中提交 issue,并打上 breaking change 标签,便于维护者补全。

迁移检查清单

结合上述各节,一次 v0.x → v1.x(含 v1.19.0)升级可按以下清单落地:

  1. 导入语句:全局替换 import { axios }import axios from "axios"
  2. 拦截器:请求拦截器参数类型改为 InternalAxiosRequestConfig;同步拦截器若依赖“拒绝处理器返回值作为新配置”的旧预期,按 lib/core/Axios.js#L211-L240 的新语义调整;
  3. 请求头:删除所有 headers.common 访问路径,默认头改写到 axios.defaults.headers
  4. 表单上传:移除手动的 multipart/form-data 头,依赖自动设置;
  5. 查询参数:核对后端的 URL 编码期望(裸方括号 vs 百分号编码、点记法 vs 方括号记法),必要时通过 paramsSerializer.serialize 注入 qs 等自定义序列化器;
  6. URL 合法性:将 https:example.com 之类畸形地址修正为 https://example.com,避免触发 ERR_INVALID_URL
  7. 内部依赖:排查并替换对 axios/lib/* 内部模块的引用,仅使用 index.js 导出的公共 API。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
docsdocs
暂无描述
Markdown
889
5.78 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.17 K
341