Axios HTTP/2 实战指南:httpVersion 与 http2Options 配置详解及源码实现剖析
本文围绕 Axios 的 HTTP/2 实验性支持展开(Node.js 环境专用,v1.13.0+ 引入),系统讲解 httpVersion 与 http2Options 两个配置项的用法、默认值与限制,并结合 lib/adapters/http.js 与 lib/helpers/Http2Sessions.js 的源码实现,说明会话池复用、空闲超时关闭(sessionTimeout)以及重定向、代理等不支持场景背后的真实调用链,帮助你在服务端场景中安全、高效地启用 HTTP/2 请求。
特性定位:实验性、仅限 Node.js
HTTP/2 的实验性支持是在 http 适配器(即 Node.js 端适配器)中于 v1.13.0 版本加入的,CHANGELOG 中记录了该特性条目(http: add HTTP2 support)。这意味着:
- 仅在 Node.js 环境中可用。浏览器/React Native 构建中,打包器通过
browser字段把 lib/adapters/http.js 替换为lib/helpers/null.js,HTTP/2 代码路径永远不会被执行(见 lib/helpers/Http2Sessions.js 顶部的注释说明); - 该特性仍标记为 Experimental,官方文档明确提示:API 可能在未来的次要或补丁版本中发生变化。
基本用法:httpVersion 选择协议版本
使用 httpVersion 选项为单次请求选择协议版本,将其设置为 2 即启用 HTTP/2:
const { data, headers, status } = await axios.post(
"https://httpbin.org/post",
form,
{
httpVersion: 2,
},
);
httpVersion 的默认值是 1(HTTP/1.x)。从 TypeScript 类型定义看,该字段被约束为 1 | 2 的联合字面量类型(见 index.d.ts):
httpVersion?: 1 | 2;
http2Options?: Record<string, any> & {
sessionTimeout?: number;
};
在 lib/adapters/http.js 中,适配器对 httpVersion 做了严格的运行时校验:
- 未显式提供时回退为
1; - 先做
+httpVersion数值化转换,若结果不是数字(Number.isNaN),抛出TypeError: Invalid protocol version: '...' is not a number; - 若非
1或2,抛出TypeError: Unsupported protocol version '...'; - 最终通过
const isHttp2 = httpVersion === 2决定走哪条传输通道。
http2Options:透传原生选项与 sessionTimeout
http2Options 配置对象用于向内部的 session.request() 调用透传 Node.js 内置 http2 模块支持的原生选项,其中包括一个 axios 自定义参数 sessionTimeout,控制空闲 HTTP/2 会话在被关闭前保活多久(单位毫秒),默认值为 1000ms:
{
httpVersion: 2,
http2Options: {
rejectUnauthorized: false, // 接受自签名证书(仅限开发环境)
sessionTimeout: 5000, // 空闲会话保活 5 秒
},
}
sessionTimeout 的源码实现
sessionTimeout 的行为由 lib/helpers/Http2Sessions.js 实现,核心逻辑如下:
- 默认值注入:
getSession(authority, options)会用Object.assign把{ sessionTimeout: 1000 }与传入选项合并,未传时即得到默认的1000ms(对应 Http2Sessions.js#L16-L23); - 包装 request 方法:当
sessionTimeout != null时,实现会对session.request做一层包装,用streamsCount跟踪打开中的流。每次新请求会清除待触发的空闲定时器;当某个流触发close事件后,只有当计数归零(即没有任何在途流)时才启动setTimeout(sessionTimeout)的关闭计时(见 Http2Sessions.js#L80-L106); - 计时到期自动回收:定时器触发后执行
removeSession()——从池中移除该 authority 的会话条目、清除定时器,并在会话未关闭时调用session.close(),防止空闲连接长期占用资源; - 异常自愈:会话的
close/error事件都会触发removeSession(),失败的会话不会残留在池中;且会话真正关闭时会主动clearTimeout,避免定时器在无谓地延长 Node 事件循环的存活时间。
这些行为均有直接对应的单元测试覆盖,例如 tests/unit/helpers/Http2Sessions.test.js 验证了:
- 相同 authority 与相同选项会复用同一缓存会话(
http2.connect只调用一次); - 不同 authority、或相同 authority 但选项不同(如
sessionTimeout: 1000vs5000)会各自建立独立会话; - 已
destroyed/closed/ 触发过close或error事件的会话不会被复用; - 最后一个流结束后经过
sessionTimeout才关闭会话;新流打开会取消待触发的空闲定时器;仍有流打开时不关闭; - 不传选项时默认
sessionTimeout为1000ms(999ms 不关闭、到 1000ms 关闭);sessionTimeout: null时不安装 request 包装器。
会话池与请求流程
Http2Sessions 实例在 lib/adapters/http.js 中作为模块级单例创建(const http2Sessions = new Http2Sessions()),为进程内所有 HTTP/2 请求提供会话复用。http2Transport.request() 的处理流程(见 http.js#L511-L557):
- 构造 authority:按
protocol://hostname:port拼接(https 缺省端口 443,http 缺省 80),作为会话池的缓存键; - 获取会话:
http2Sessions.getSession(authority, http2Options),同 authority 且选项深相等(util.isDeepStrictEqual)的存活会话直接复用; - 映射伪头(pseudo-headers):HTTP/2 要求用
:scheme、:method、:path伪头描述请求,适配器从 axios 的options中提取并写入,然后把除伪头外的普通请求头逐一复制到http2Headers; - 发起请求:
session.request(http2Headers)得到双向流req;监听response事件,把:status伪头取出转为response.statusCode,其余响应头放入response.headers,随后回调给上层走统一的settle/数据解析流程。
此外,适配器在构造请求选项时,如果同时配置了 lookup 函数,会将其合并进 http2Options(Object.assign(Object.create(null), http2Options, { lookup }),见 http.js#L925-L927),使自定义 DNS 解析在 HTTP/2 路径下同样生效。
完整示例:multipart 上传 + 进度跟踪
下面的示例通过 HTTP/2 发送 multipart/form-data POST 请求,并同时跟踪上传与下载进度(来自 docs/es/pages/advanced/http2.md 的完整示例):
const form = new FormData();
form.append("foo", "123");
const { data, headers, status } = await axios.post(
"https://httpbin.org/post",
form,
{
httpVersion: 2,
http2Options: {
// rejectUnauthorized: false,
// sessionTimeout: 1000
},
onUploadProgress(e) {
console.log("upload progress", e);
},
onDownloadProgress(e) {
console.log("download progress", e);
},
responseType: "arraybuffer",
},
);
注意两点:
onUploadProgress/onDownloadProgress回调在 HTTP/2 传输下与 HTTP/1.x 行为一致,可直接复用现有的进度展示逻辑;- 示例中
http2Options的字段以注释形式给出,说明这两项都是可选的——不传时sessionTimeout取默认1000ms,TLS 校验保持 Node.js 默认行为。
限制与注意事项
重定向不被支持
HTTP/2 适配器目前不会自动跟随重定向:使用 httpVersion: 2 发出的请求若收到 3xx 响应,axios 不会像 HTTP/1.x 路径(基于 follow-redirects 传输)那样继续请求新地址。对此有两种处理方式:
- 在业务代码中手动处理
3xx响应,自行发起后续请求; - 对依赖重定向的端点,保持
httpVersion: 1(或不设置)走 HTTP/1.x。
这一点与源码结构一致:HTTP/1.x 路径在 maxRedirects !== 0 时会选用支持重定向跟随的传输并注入 beforeRedirects 逻辑,而 isHttp2 分支直接选用 http2Transport,不存在重定向跟随逻辑(见 http.js#L1012-L1033)。
代理不被支持
从源码看,HTTP/2 传输独立于 HTTP/1 的 agent 建立连接,无法应用 axios 解析的环境代理或 agent 级代理。因此当请求同时满足 isHttp2 且检测到代理已生效(proxyApplied)时,适配器会直接以 AxiosError.ERR_NOT_SUPPORT 拒绝请求,错误信息为 HTTP/2 requests with a proxy are not supported(见 http.js#L1012-L1021)。需要经代理访问的 HTTP/2 端点请保留 HTTP/1.x。
实验性声明
HTTP/2 支持当前仍为实验性,API 可能在未来版本中调整;生产环境引入前建议锁定 axios 版本并关注后续版本说明。
配置参考
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
httpVersion |
number |
1 |
要使用的 HTTP 协议版本。设为 2 启用 HTTP/2。仅接受 1 或 2,非法值会抛出 TypeError。 |
http2Options.sessionTimeout |
number |
1000 |
空闲 HTTP/2 会话在关闭前的保活时间(毫秒)。最后一个流结束后开始计时;新流打开会重置计时;设为 null 可关闭自动回收。 |
http2Options 内还可以传递 Node.js 内置 http2 模块支持的其它原生 session.request() 选项(例如 rejectUnauthorized 等 TLS 相关参数)。注意:由于会话复用要求选项深度相等才会命中缓存,同一 authority 下传入不同的 http2Options(如不同的 sessionTimeout 或 TLS 参数)会建立各自独立的 HTTP/2 会话,这是 tests/unit/helpers/Http2Sessions.test.js 中"creates a new session when options differ for the same authority"用例所验证的行为。
相关源码与测试索引
| 位置 | 内容 |
|---|---|
| docs/es/pages/advanced/http2.md(及 英文版) | 本文对应的官方 HTTP/2 文档 |
| lib/adapters/http.js | http2Transport:authority 构造、伪头映射与响应解析 |
| lib/adapters/http.js | httpVersion 校验与 isHttp2 分流 |
| lib/helpers/Http2Sessions.js | 会话池:复用判定、sessionTimeout 空闲回收、错误自愈 |
| tests/unit/helpers/Http2Sessions.test.js | 会话池行为的单元测试(复用、超时、清理、默认值) |
| index.d.ts | httpVersion / http2Options 的 TypeScript 类型定义 |
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00