npm install 总超时?Clash 分流 registry 与 tarball CDN 实测步骤(2026)
为什么浏览器正常,terminal 仍然 ETIMEDOUT
很多前端与 Node 项目在受限跨境网络里最恼人的一节,其实不是写业务代码,而是npm install、pnpm install 或 Yarn 装依赖时出现的长转圈:ETIMEDOUT、ENOTFOUND、卡在 fetch 半段、或者直接停在某一个大包上不前进。桌面上 Chrome 可能已经走顺了开发者代理,但一旦换到Terminal、IDE 内置 Terminal、Docker 容器、CI Runner,链路就会分叉——HTTP 出站可能仍然直连registry.npmjs.org,或者元数据走到了代理却忘了把后续 tarball CDN 主机收进同名策略组。
本文的目标是给你一套可复制、可按日志迭代的写法:先说清一次安装里谁是 registry、谁是 tarball CDN,再演示如何在 Mihomo/Clash 中用DOMAIN-SUFFIX/DOMAIN-KEYWORD把它们统一丢进单独的 NPM_REGISTRY 策略组,同时用 GEOIP CN 或等价国内集合把阿里云、腾讯云、CDN 控制台、公司内部 OA 与国内镜像留在 DIRECT。若你对 mode: rule、规则顺序不熟,可先读 Clash 规则分流总览;若还没搞定订阅导入,可对照 订阅导入教程 把底座跑通再回到本文专项。
先把链路拆开:registry、tarball、pnpm-store
从协议视角看,官方 npm registry 会先返回一包 JSON:name、versions、以及每个版本条目里的 tarball URL。多数情况下 tarball 仍以 https://registry.npmjs.org/…/-/*.tgz 这种形式托管在同一棵域名树下,但一旦遇到对象存储跳转、CDN 边缘或某些历史兼容路径,就会在日志中出现完全不同的二级域或边缘节点。此时如果你只在规则里写了一行「registry.npmjs.org→PROXY」,而客户端随后跟去的却是另一个 FQDN,就会表现为「半截成功、半截直连烂路」,看起来就像pnpm并行拉几十个包时某一个线程永远 pending。
pnpm Classic 会使用 content-address store,更多并发意味着更多边缘主机名暴露在连接面板;yarn berry 若配置了 enableGlobalCache 或与 Corepack 耦合,还会在 corporate 环境里触发额外 registry 前缀。Yarn Classic(yarn 1.x)则往往继续围绕 registry.yarnpkg.com 或回源官方 registry。但无论包管理差异如何,拆分策略的第一性原理不变——把你从 verbose 与实际连接记录里看见的每一个外网依赖域名收进同名策略组。
环境与代理对齐:别把「编辑器能上网」误认为「NODE 也行」
常见踩坑有几种:仅在 macOS/Windows GUI 勾选系统代理却让 Terminal 跳过;只对 Git 配置了 http.proxy 却遗漏 Node;在 WSL/Linux 虚拟机里误以为 127.0.0.1:7890 指的就是宿主上的 Clash 端口。TUN 可以避免大量重复配置,但并非银弹: systemd-resolved 、公司 SSL 巡检、抑或容器网络命名空间仍会让「看起来像直连」的包溜出去。
建议你在排障的第一步用一个小文件下载或 curl -I https://registry.npmjs.org/ 验证——注意要用和 CI 完全相同的执行环境。HTTPS_PROXY 能解决部分场景,但更推荐让内核按照规则替你挑出口,再配合 NO_PROXY(或等价 bypass 列表)把内网 NPM 私服、局域网 Registry、以及必须走公司线路的 OA 前缀排除。Docker Build 中使用 pnpm 或 yarn 时请参考 Docker Desktop 对接 Clash 代理,避免引擎与容器两套代理互相打架——本文专注宿主与裸终端 Node,思路可平移到容器。mcp.json、IDE Agent 等与 LLM/工具链耦合场景可交叉阅读 MCP 与开发者代理分流。
YAML 片段:单独的 NPM 策略组 + 置顶域名
下面是一份结构示意,请把占位符改成你订阅里真实存在的分组名,并把「国内镜像」「公司 NPM」提前插入更高优先级:GFW 规则集若没有覆盖某条 CDN 后缀,就把它补在后面;远端规则与你的本地条目冲突时的排查可参考 Rule Provider 排障笔记。
proxy-groups:
- name: "npm-registry-out"
type: select
proxies:
- "稳定跨境节点"
- "DIRECT"
- "REJECT"
rules:
# corporate mirror / OA — keep BEFORE broad proxy selectors
- DOMAIN-SUFFIX,npm.company.internal,DIRECT
# public China mirrors prefer DIRECT when inside mainland
- DOMAIN-SUFFIX,npmmirror.com,DIRECT
- GEOIP,cn,DIRECT,no-resolve
# official endpoints (extend list after inspecting logs & lockfiles)
- DOMAIN-SUFFIX,registry.npmjs.org,npm-registry-out
- DOMAIN-SUFFIX,npmjs.org,npm-registry-out
- DOMAIN-KEYWORD,npm-registry,npm-registry-out
# when tarball lands on CDN edges, duplicate them here once discovered
- MATCH,兜底策略
MATCH 上方的顺序至关重要:先国内直连与国内镜像直通,再兜底代理,否则你会把腾讯云上的静态资源硬生生拖进出海带宽。npm 生态里也不乏把 tarball 镜像到 GitHub Releases 的包,如果你在拉依赖时经常看到 objects.githubusercontent.com,请把它归入「Git/GitHub 大件」另一条策略或沿用你在 聚合 API Clash 分流 里已经用过的 GitHub CDN 处理方式,而不要简单重复写多套互相矛盾的 PROXY/DIRECT。
DNS 与合规提示:若使用 fake-ip 或第三方 DoH,请确认解析链路不会把 registry.npmjs.org 劫持到污染的地址;并请遵守你与雇主签署的网络与外发政策,本文为技术排障不构成对受限资源的访问背书。
如何用 verbose 实测:一次冷安装能看见什么
最省时间的实测流程是删掉 node_modules、必要时暂时移动 pnpm-store/Yarn Cache,然后执行 npm install --registry=https://registry.npmjs.org/ --verbose。pnpm 可配合 --reporter ndjson 或直接观察连接面板。Yarn Classic 可执行 yarn config set verbose true 或用环境变量调高网络日志。pnpm 若显示大量 TAR_DOWNLOAD 相关事件,把注意力放在紧接着出现的真实 URL hostname——把它抄进草稿本,随后在 Clash 客户端「连接」视图里双击确认策略命中。
- 固定一个节点,关掉自动轮换,先在单一出口下完成一次完整冷安装样本。
- 记录第一次失败或最慢的一组 hostname,将它们全部映射到
npm-registry-out同名组。 - 若仍然偶发断开,可先临时调高
fetch-timeout(npm config set fetch-timeout 120000)做对照——持久根因多数仍是节点抖动或半截直连。 - 热缓存重装一次,核对命中是否全部一致,避免出现「冷热路径走了不同后缀」的假阳性。
TUN、pnpm-fetch 与公司 SSL 中间人检测
不少企业网关会对未安装根证书的终端直接中断 TLS,看起来像代理坏了。此时即便写了完美的 Clash 分流也无效,需要先处理证书导入或切换到经批准的 NPM 私服。Yarn Berry 若启用checksumBehavior也会对 tarball 哈希非常敏感——镜像不完整或中间缓存篡改都会表现为安装失败。TUN 模式细节可参考 Clash TUN 与全局代理权衡;若你连 DNS UDP 也出现异常(例如延迟测试全员飘红),可先按 DNS/UDP STUN 专文自检。
小提示:若项目使用 Corepack shim 去激活老版本 Yarn Classic,记得在同一个 shell session 导出与安装命令一致的NODE_OPTIONS与代理相关环境变量,避免出现「pnpm 通了、yarn 又挂」的假对比。
常见问题补充
只写 registry.npmjs.org,为什么仍会一半直连?
因为第二阶段 tarball 可能解析到了其它 CDN/对象存储后缀;必须用日志确认并追加。Yarn Berry 与pnpm也可能先读本地 store 再走网络,误判时看起来像「卡在解析」。
国内镜像和官方并行会冲突吗?
不会,只要你把旧的淘宝源写法彻底迁移到registry.npmmirror.com一类的现行镜像入口(常见域名后缀如npmmirror.com),并把镜像规则放在更高优先级的DIRECT。Yarn Berry 如仍强制某 scope 走高延迟海外 registry,再为该 scope mirror 单列规则。
WSL/远程开发容器里该怎么做?
原则与WSL 路由/MTU 专文一致:127.0.0.1语义会变化,优先考虑 TUN 或宿主可被容器访问的路由 IP;容器里若直接跑pnpm或Yarn,记得把HTTPS_PROXY对齐到可被容器路由到的 Clash 监听地址。
收尾:把碎片化规则升级成你自己的「npm 后缀表」
当你在连接面板把所有安装阶段重复的 hostname 归档成一份本地 rule-provider,就能像维护依赖锁文件一样演进:新增一条 CDN→策略组映射,跑一次冷安装复核,再在 PR 注释里写明对应包名。Yarn、pnpm Classic、npm CLI 三者都能复用同一种思维模型,只是把并发与缓存的路径差异记在心上。
再次提醒:任何跨境访问须符合当地法律与你的用工协议;若在金融、医疗等高监管行业,请以安全团队提供的出口为准,本文不承担合规解释责任。
小结
解决 npm install 超时从来不是「只靠换个 registry 镜像」,而是对齐终端真实出口、补足tarball CDN 后缀,并让pnpm、Yarn 与npm CLI共享同一策略组。GEOIP CN与国内镜像直通写在前、官方 registry 走代理兜底写在后,可以把误代理降到最低。市面上不少只靠浏览器插件或临时环境变量的做法,往往在 IDE、Corepack、pnpm 并行 store 与公司 SSL 组合场景里反复露馅;而把海外域名整块丢进粗暴全局代理又会拖慢国内静态资源与工作台。ClashSource坚持用 Meta 内核可读的 YAML 段落把链路讲透,再配合订阅自检与节点选择,就能把这份「npm 后缀表」升级成你自己的小基础设施。pnpm 拉超大 monorepo 时若只差最后一口气,不妨从本站 下载页 选取与你操作系统匹配的桌面端,装好后再跑一轮冷安装,很快就能判断 tarball 是否已经全部命中同名策略组。→ 立即免费下载 Clash,开启流畅上网新体验