axios 维护者手册:Issue 分诊、PR 工程规则与供应链安全红线
本文基于 axios 仓库的官方协作者指南 COLLABORATOR_GUIDE.md 展开,系统梳理 axios 协作者(collaborator)从 Issue 分诊、社区答疑到 PR 审查、安全披露的完整职责边界。读完本文,你将掌握 axios 项目的一体化工程规则:为什么必须同时覆盖 XHR、Fetch 和 Node HTTP 三种适配器、为什么 package-lock.json 要过 lockfile-lint、为什么依赖更新 PR 只允许维护者或机器人提交——每一条规则都能在仓库源码、CI 配置和测试布局中找到对应的落地证据。
协作者角色与文档体系
axios 的协作者不只是“有合并权限的贡献者”,而是承担项目管理工作的人:分诊 Issue、回答社区问题、审查 PR、处理安全报告。COLLABORATOR_GUIDE.md 只覆盖这些“管理职责”,而架构、生命周期、安全敏感代码与编码约定则以 AGENTS.md 为唯一权威指南(canonical contributor guide),两者分工明确、互为引用。
围绕协作者职责,仓库还有一组配套文档与配置,理解它们才能理解规则的来源:
| 文件 | 作用 |
|---|---|
| AGENTS.md | 权威贡献者指南:架构边界、命名约定、错误处理、拦截器顺序、请求生命周期、常见坑、测试布局、安全敏感代码清单 |
| THREATMODEL.md | 运行时与供应链双重威胁模型,安全敏感变更必须对照它评估 |
| SECURITY.md | 安全策略:漏洞上报走 GitHub security advisory,60 天内解决并披露 |
| CODE_OF_CONDUCT.md | 行为准则,协作者负有维护与执行的义务 |
| CONTRIBUTING.md | 面向普通贡献者的规范:Conventional Commits、测试、文档同步 |
| .github/CODEOWNERS | 路径级审查人配置,/lib/、/package.json、/SECURITY.md 等敏感路径均有专属 owner |
| .github/dependabot.yml | 依赖与 Actions 更新的自动化配置,含 7 天冷却期 |
| .github/PULL_REQUEST_TEMPLATE.md | PR 模板,内置“类型声明双文件同步”“无破坏性变更”等检查项 |
第一条硬性要求是行为准则:协作者必须阅读 CODE_OF_CONDUCT.md 并协助执行它,保持社区友好与包容。这看似是软性要求,但在 axios 的分诊实践中它直接影响对 Issue 和 PR 的处置方式(例如“礼貌地尽早拒绝不属于 axios 的功能请求”)。
Issue 分诊:规则与关闭边界
协作者的日常第一份工作是分诊 Issue。指南给出了四条可操作规则:
- 打标签并按需回复。axios 的 PR/自动化流程依赖标签体系,例如 dependabot.yml 中为所有自动化 PR 统一打上
commit::chore和type::automated-pr标签,分诊时保持标签一致才能让后续自动化(如 release 工具)正常工作。 - Bug 报告先要最小复现。在深入分诊前,要求报告者提供 axios 版本、运行环境、请求/响应细节。仓库的 Issue 模板 .github/ISSUE_TEMPLATE.md 正好内置了这些字段:Axios 版本、Adapter(xhr / http / fetch)、Runtime(如 Node 20、Chrome 124、Bun、Deno)、OS 及附加上下文(框架、打包器、代理等)——分诊时可以直接对照模板检查信息是否完整。
- 与 axios 无直接关联的 Issue 转为 Discussion,避免 Issue 区被环境配置类、JavaScript 基础类问题淹没。
- 关闭 Issue 有严格边界:仅当问题已解决、修复已合并、报告缺乏足够细节或复现、或报告者主动要求关闭时才能关闭;不得以“长时间无活动”为由关闭。axios 希望保留历史记录,以便日后有新信息进来时仍能响应。
回答社区问题:顺手修复文档缺口
指南要求协作者“有帮助且有耐心”,并给出了一条高价值的操作原则:如果问题源于文档不清晰,应更新文档并考虑增加示例,而不仅仅在 Issue 线程里回答一次。axios 的文档体系横跨 docs/pages/ 下的英文主文档与 docs/zh/pages/、docs/es/pages/、docs/fr/pages/ 多语言版本,同时根目录有 README.md 与 MIGRATION_GUIDE.md,一个“文档缺口”往往意味着多处需要同步。
边界同样明确:协作者没有被义务去教 JavaScript 或无关工具,这类问题应礼貌地引导到社区渠道(Issue 模板也明确建议用法类问题去 Stack Overflow 的 axios 标签)。
PR 工程规则:从范围适配到错误对象约定
这是指南最重的一块。每条规则都能在当前仓库中找到落地证据。
范围适配与三适配器覆盖
- 变更必须落在 axios 的职责边界内。属于用户代码或插件能解决的功能,应尽早、礼貌地拒绝——这与 AGENTS.md 的“架构边界”一脉相承:
lib/core/只放领域逻辑,lib/adapters/只做 I/O,lib/helpers/保持通用可复用。 - 相关行为必须覆盖 XHR、Fetch、Node HTTP 三种适配器,且按能力(capability)检测而非按环境名检测。这一点在 AGENTS.md 中有明确的实现锚点:默认适配器偏好为
['xhr', 'http', 'fetch'],选择逻辑在 lib/adapters/adapters.js 中做能力探测。测试布局也按运行时组织——单元测试在 tests/unit/,浏览器端用例集中在 tests/browser/(如 adapter.browser.test.js),Node 侧打包/导入兼容性则由 tests/smoke/cjs/ 与 tests/smoke/esm/ 的用例集覆盖。
类型声明双文件同步
公共 API 变更必须同时更新 index.d.ts(ESM)与 index.d.cts(CJS,export = axios 风格)。两个文件在仓库根目录并列存在:index.d.ts 约 23KB、index.d.cts 约 23KB,分别服务 ESM 消费方和 CommonJS 消费方。AGENTS.md 的“Package Shape”一节强调运行时导出、两个类型文件必须保持同步;.github/PULL_REQUEST_TEMPLATE.md 的 Checklist 也内置了“Docs/types updated if public API changed (index.d.ts and index.d.cts)”这一勾选项。类型兼容性的回归由 tests/module/cjs(TypeScript 4.9)和 tests/module/esm(TypeScript 5.x)两个模块套件实际执行。
错误对象约定:永远抛出 AxiosError
axios 自身产生的失败必须抛出带合适 code 的 AxiosError,绝不允许裸 Error;第三方错误用 AxiosError.from 包装。源码中这一约定是强约束:
- 规范 code 列表集中在 lib/core/AxiosError.js(约 L204-L217),包括
ERR_BAD_OPTION_VALUE、ERR_BAD_OPTION、ERR_NETWORK、ERR_FR_TOO_MANY_REDIRECTS、ERR_DEPRECATED、ERR_BAD_RESPONSE、ERR_BAD_REQUEST、ERR_CANCELED、ERR_NOT_SUPPORT、ERR_INVALID_URL、ERR_FORM_DATA_DEPTH_EXCEEDED等,另有ECONNABORTED、ETIMEDOUT、ECONNREFUSED等。 AxiosError.from(error, code, config, request, response, customProps)(lib/core/AxiosError.js#L99)是包装第三方错误的标准入口。从源码看,它特意处理了 Node 双栈连接失败产生的AggregateError(message为空、细节在errors[]中)的场景,并且把被包装错误挂到非可枚举的cause上——因为被包装对象常带循环内部结构(socket、request、agent),可枚举的cause会让 pino/winston 等结构化日志器在序列化时抛 “Converting circular structure to JSON”(见源码注释中引用的回归 #6982/#7205)。
调用方约定形如:
import { AxiosError } from 'axios';
// 包装第三方错误(如底层网络库抛出的原生 Error)
throw AxiosError.from(err, 'ERR_NETWORK', config, request, response);
// 消费端可按 code 精确分支
catch (error) {
if (error instanceof AxiosError) {
switch (error.code) {
case 'ECONNABORTED': /* 超时 */ break;
case 'ERR_CANCELED': /* 主动取消 */ break;
/* ... */
}
}
}
AGENTS.md 还要求抛出时传齐 (message, code, config, request, response) 五个参数,保证消费端可以做内省(introspection);配置项校验统一走 validator helper(lib/helpers/validator.js),不要发明临时校验路径。
测试与 CI 门禁:不允许合并红 PR
指南要求:变更必须有单元测试覆盖;涉及打包或运行时面(packaging/runtime surface)时同步更新 browser、smoke 或 module 套件;lint 与测试通过前不得进入评审,不得合并红 PR。CI 侧的证据在 .github/workflows/run-ci.yml:每个 PR 触发 npm ci --ignore-scripts → npm run lint → npm run build → 安装 Playwright → npm run test:vitest:unit → npm run test:vitest:browser:headless → npm pack → Dependency Review → 上传 tarball 产物,随后是 CJS smoke 矩阵(Node 12/14/16/18)与 ESM/Bun/Deno 套件。从源码结构看,AGENTS.md 描述的 CI 顺序(install → build → Playwright → unit → browser headless → pack → module/smoke → Bun/Deno)与该 workflow 一一对应,这就是“红 PR 不能合并”的机械保障。
本地可对照执行的命令(来自 AGENTS.md 的 Commands 一节):
# 构建发布产物(gulp clear 清空 dist/,Rollup 产出浏览器 ESM/UMD/CJS 与 Node CJS 包)
npm run build
# 仅 lint 源码;聚焦单文件
npm run lint
npx eslint lib/path/to/file.js
# 单元测试;聚焦单个用例
npm run test:vitest:unit
npm run test:vitest:unit -- tests/unit/path.test.js
# 浏览器测试需先装 Playwright
npx playwright install
npm run test:vitest:browser:headless
依赖红线:lockfile-lint 与依赖更新管控
指南中有两条互相咬合的规则:
- 未经讨论不得新增运行时依赖——axios 的依赖面被刻意保持极小(
package.json的 runtime dependencies 仅follow-redirects、form-data、proxy-from-env三个)。 package-lock.json变更必须让lockfile-lint满意:所有解析地址必须是 npm HTTPS 主机,且每条目必须带 integrity 哈希。
仓库证据在 .github/workflows/lockfile-lint.yml:只要 PR 触碰 package.json/package-lock.json 就会触发,执行
npx --yes lockfile-lint@4.14.0 \
--type npm \
--path package-lock.json \
--validate-https \
--allowed-hosts npm \
--validate-integrity \
--validate-package-names \
--empty-hostname false
workflow 注释说明其目的:捕获依赖更新 PR 中把地址换成镜像、改用 git/file: URL 或剥离 integrity 哈希的篡改。注意它用 npx 按版本名直接拉取 lockfile-lint@4.14.0 而非走 devDependencies,注释解释这是防呆设计——“被污染的依赖树无法压制此检查”。
- 包、lockfile 与 GitHub Actions 的更新 PR 是维护者/机器人专属。外部协作者提交的这类 PR 应直接关闭。.github/dependabot.yml 展示了官方更新通道:npm 与 github-actions 两个生态均为 weekly 节奏,标签统一为
commit::chore+type::automated-pr,且
cooldown:
default-days: 7
即保持 7 天的 Dependabot 冷却期,仅在严重漏洞需要维护者手动介入时才绕过。npm 侧还做了分组(production/development 各归 minor/patch)、major 更新默认忽略、单 PR 上限 5 个。CONTRIBUTING.md 与 .github/PULL_REQUEST_TEMPLATE.md 也重复声明了这条规则,确保普通贡献者第一时间知道。
安全敏感变更:附加审查与回归测试
指南列出了安全敏感变更的清单:URL 构建、重定向、代理/环境变量处理、XSRF、socket 路径、解压限制、原型遍历(prototype walking)、适配器。这类变更需要“额外审视 + 聚焦回归测试”,并对照 THREATMODEL.md——该文档从运行时与 SDLC 两个系统建模资产、信任边界、威胁者与缓解措施,缓解措施会直接引用仓库文件。
AGENTS.md 的“Security-Sensitive Code”一节给出了与之对应的代码级约束,可作为协作者审查 PR 时的 checklist:
- 影响行为的配置读取不得使用原型链遍历式读取(
in、解构、对不可信 config 的直接config.foo),要用自有属性检查(如utils.hasOwnProp); - 新的 merge/对象物化代码必须继续过滤
__proto__、constructor、prototype,此类回归直接定性为安全 bug; withXSRFToken的跨域行为必须保持显式:只有true才强制附加跨域 XSRF 头;- 不得在无回归测试(凭据泄漏、SSRF 类用例)覆盖的情况下削弱
beforeRedirect、proxy、socketPath防护。
版本语义:标题、分级与目标分支
- PR 标题必须使用 Conventional Commits(
fix:、feat:、chore:、docs:等前缀)。CONTRIBUTING.md 对普通贡献者同样要求,因为 release 工具链直接依赖提交类型生成版本号与 changelog。 - 每个 PR 要声明自己是 patch、minor 还是 breaking。当前维护线是
v1.x分支(lockfile-lint.yml 中push: branches: [v1.x]也印证这是受保护的维护分支);破坏性变更必须发往其他目标分支,并在 PR 描述中明确标注。 - 删除功能前必须先警告(warn):新增公共 API 必须可预测、与现有选项风格一致、且同步文档。
审查与合并流程:单人项目下的双人保险
合并前的规则链条:
- 至少一名维护者(maintainer)必须审查并批准 PR 才能合并。从 .github/CODEOWNERS 看,axios 目前实际是单一 owner 维护
/lib/、类型声明、构建与 CI 等全部敏感路径;文件注释坦承了这一点:单人配置下路径级规则无法强制“不同的第二名审查人”,但它们能在审查界面显式高亮敏感路径变更,并为将来增加维护者预置作用域归属。 - 拿不准影响面时,要求第二意见(second opinion);PR 描述里点明 breaking change 并送对分支。
- Bug fix 必须附带复现该问题的测试,并验证修复——即先红后绿。
- 评审意见要尽快处理;如果自己无法完成修改,要明说,让他人接手。
关于“stale PR”有一条用 IMPORTANT 标注的明确时限:等待变更请求的回应最多 28 天,之后按 stale 关闭;关闭后要么由维护者主导 PR 处理该问题,要么开 Issue 交给其他贡献者。原作者若想继续,应从正确目标分支的最新版本重建 PR、处理全部反馈并请求维护者审查。这条规则把“不关闭无活动 Issue”与“不无限期挂起 PR”之间的张力做了显式平衡。
安全披露:公共 Issue 里只字不谈细节
当有人在公共 Issue 中报告疑似漏洞时的处置流程:
- 不在线程中讨论任何细节;
- 引导对方走 SECURITY.md 描述的流程,即 GitHub 私有 security advisory 通道;
- 视情况关闭或隐藏该 Issue。
SECURITY.md 补充了协作者后续可能接触到的完整披露政策:指派主处理人,承诺60 天内解决并公开披露有效 advisory(60 天是底线而非目标——修不完也要在第 60 天发布带缓解建议的 advisory);超出范围的报告在 ≤3 天的分诊窗口内向报告者解释关闭(依据 THREATMODEL.md 的显式非目标);被在野利用的漏洞按 incident 处理,补丁验证后立刻发布。研究者在报告前还应阅读 THREATMODEL.md,其中定义了运行时与供应链两套模型的范围与已知缺口。
红线清单:协作者不应做的事
指南最后用负面清单划出四条硬边界,每一条都对应仓库中可验证的机制:
| 红线 | 仓库证据 |
|---|---|
| 未经讨论不新增运行时依赖(依赖面刻意极小) | package.json 的 runtime 依赖仅三个;AGENTS.md 重申 |
| 不合并外部协作者的包/lockfile/Actions 版本更新 PR | dependabot.yml 的 7 天冷却 + 标签体系;CONTRIBUTING.md 声明 |
不得在 .npmrc 中禁用 ignore-scripts 或以其他方式削弱安装期安全 |
仓库 .npmrc 内容为 ignore-scripts=true;CI 使用 npm ci --ignore-scripts;AGENTS.md 要求“不得移除 ignore-scripts=true,需要 git hooks 时改用 npm rebuild husky && npx husky 一次性恢复” |
不得在无回归测试覆盖的情况下削弱 beforeRedirect、proxy、socketPath、XSRF 或原型污染防护 |
THREATMODEL.md 的运行时威胁模型;AGENTS.md 的 Security-Sensitive Code 一节 |
其中 ignore-scripts 一条值得展开:axios 把“安装期代码执行”视为供应链攻击面,默认跳过所有依赖的 install 脚本。注意 AGENTS.md 的补充——构建/测试/lint 工具仍会执行依赖代码,所以能用聚焦检查(如单文件 eslint、单个 vitest 用例)证明变更时,应避免不必要的完整构建。
结语:慢一点,好过发一个回归
COLLABORATOR_GUIDE.md 的收尾给出了 axios 协作者文化的基线:“我们宁可慢一点,也不发布一个回归”(We would rather move a little slower than ship a regression)。遇到拿不准的处置,先问另一位协作者;对职责有疑问,联系维护者。
把这份指南和仓库配置放在一起读,可以看出 axios 的治理设计是一个闭环:Issue 模板保证分诊信息齐全 → Conventional Commits 与目标分支规则保证版本语义 → 三适配器测试与类型双文件同步保证行为面完整 → lockfile-lint、ignore-scripts、依赖更新管控构成供应链门禁 → THREATMODEL 与 SECURITY 流程兜住漏洞处置。对任何维护 HTTP 客户端这类“基础设施级”库的团队而言,这套“文档规则 + 配置强制 + 测试兜底”的三层结构本身就是最值得借鉴的工程实践。
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