[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-strapi-article:zh:dependency-download-integrity-verification":3,"blog-article:\u002Fblog\u002Fdependency-download-integrity-verification":736,"blog-related:\u002Fblog\u002Fdependency-download-integrity-verification":737,"blog-translations:\u002Fblog\u002Fdependency-download-integrity-verification":738},{"available":4,"article":5,"relatedArticles":222,"translations":594},true,{"source":6,"id":7,"documentId":8,"translationKey":8,"locale":9,"slug":10,"path":11,"_path":11,"title":12,"description":13,"excerpt":13,"image":14,"publishedAt":15,"updatedAt":16,"author":17,"tags":18,"featured":19,"sortOrder":20,"readingTime":21,"bodyType":22,"bodyBlocks":23,"bodyHtml":221},"strapi",3983,"fbw8sgrwr6tiotnj7nyl0vfi","zh","dependency-download-integrity-verification","\u002Fblog\u002Fdependency-download-integrity-verification","如何确认开发环境通过代理下载的依赖没有损坏","先比锁文件 integrity，再做归档与解压三层校验；哈希不符时先换官方源归因，半包文件和缓存污染要用续传后复测与清缓存对照排除。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_cover_4c35505c52.webp","2026-11-06T07:39:43.949Z","2026-11-06T07:39:43.919Z","Global Proxies Team",[],false,0,3,"blocks",[24,37,43,47,55,63,71,79,87,91,95,99,103,107,111,123,127,131,135,139,143,147,151,155,159,163,167,178,182,201,205,209,213,217],{"type":25,"children":26},"paragraph",[27,30,35],{"text":28,"type":29},"依赖“下载成功”不等于“没有损坏”。npm、pnpm、pip、Go、Maven 各有各的可信校验来源，但并非都默认开启、也不是都记录在锁文件里；正确顺序是先确认项目启用了哪种校验并比哈希，再看归档和安装结果。","text",{"text":31,"type":29,"marks":32},"代理IP",[33],{"type":34},"bold",{"text":36,"type":29}," 参与下载时，半包文件、缓存污染和镜像未同步是三类最常见的假成功，下面按校验顺序拆开。",{"type":38,"level":39,"children":40},"heading",2,[41],{"text":42,"type":29},"先用锁文件中的 integrity 校验依赖包",{"type":25,"children":44},[45],{"text":46,"type":29},"npm 的 `package-lock.json`、pnpm 的 `pnpm-lock.yaml` 里都有 `integrity`（sha512），安装时默认参与校验。pip 需要显式 `--require-hashes` 并固定版本，哈希才生效。Go 的 `go.sum` 在模块下载时校验，`go mod verify` 只校验本地模块缓存是否被改动过，两者覆盖范围不同。Maven 仓库可能提供 `.sha1\u002F.sha256`，是否强制校验取决于仓库元数据和构建配置，需要在项目里显式配置并验证；Gradle 用 `verification-metadata.xml`。先确认校验已启用，再谈安装前后各比一次。",{"type":25,"children":48},[49,53],{"text":50,"type":29,"marks":51},"npm：",[52],{"type":34},{"text":54,"type":29}," 哈希记录在 `package-lock.json 的 integrity`，可通过 `npm ci 时自动校验` 校验。",{"type":25,"children":56},[57,61],{"text":58,"type":29,"marks":59},"pnpm：",[60],{"type":34},{"text":62,"type":29}," 哈希记录在 `pnpm-lock.yaml 的 integrity`，可通过 `pnpm install --frozen-lockfile` 校验。",{"type":25,"children":64},[65,69],{"text":66,"type":29,"marks":67},"pip：",[68],{"type":34},{"text":70,"type":29}," 哈希记录在 `requirements 的 --hash`，可通过 `pip install --require-hashes` 校验。",{"type":25,"children":72},[73,77],{"text":74,"type":29,"marks":75},"Go：",[76],{"type":34},{"text":78,"type":29}," 哈希记录在 `go.sum`，可通过 `go mod verify` 校验。",{"type":25,"children":80},[81,85],{"text":82,"type":29,"marks":83},"Maven：",[84],{"type":34},{"text":86,"type":29}," 哈希记录在 `仓库元数据中的校验和（算法依仓库而定）`，可通过 `按项目配置比对` 校验。\n锁文件里没有哈希，说明项目没启用完整性校验，先补这一层，再谈代理。",{"type":38,"level":39,"children":88},[89],{"text":90,"type":29},"从下载包、归档文件和解压内容逐层校验",{"type":25,"children":92},[93],{"text":94,"type":29},"第一层证明包没被替换，第二层证明下载字节完整，第三层才能发现解压失败、权限错误和换行符被改写。只做一层会漏：代理返回 200 但内容是错误页，包管理器哈希能抓到；解压后文件缺失，只有第三层能抓到。",{"type":25,"children":96},[97],{"text":98,"type":29},"解压后可以抽查文件数量、总大小和关键文件哈希，但这只能说明抽查范围与可信基准一致。若要确认全部文件完整，应比较完整文件清单或逐文件摘要；采用抽检时，要说明覆盖范围。",{"type":38,"level":39,"children":100},[101],{"text":102,"type":29},"检查代理中断后的断点续传和文件完整性",{"type":25,"children":104},[105],{"text":106,"type":29},"代理重置连接后，本地可能留下半包文件。文件大小对得上不能证明完整：只有固定同一来源、同一版本与同一校验算法后，哈希不一致才说明当前下载结果与基准不符，接着区分缓存、镜像和上游变化。续传要用 `Range`，同时带上强 `ETag` 或 `If-Range` 等资源验证条件，记录起止偏移和最终可信摘要；200（从头下载）与 206（追加）是两个分支，要分别确认走了哪一个，续传完成后重新校验，不能凭文件大小判断。",{"type":25,"children":108},[109],{"text":110,"type":29},"服务端不支持 `Range` 时，客户端会从头重下；这时要确认旧文件被覆盖，而不是和新数据拼接。",{"type":25,"children":112},[113,115,121],{"text":114,"type":29},"核对包管理器使用的代理协议和认证参数，可参考",{"text":116,"type":29,"marks":117},"代理设置帮助",[118],{"href":119,"type":120},"https:\u002F\u002Fhelp.quanqiudaili.com\u002Fdocs\u002Fproxy-Settings","link",{"text":122,"type":29},"。",{"type":38,"level":39,"children":124},[125],{"text":126,"type":29},"对比缓存命中和重新下载后的依赖校验结果",{"type":25,"children":128},[129],{"text":130,"type":29},"对照实验只改缓存一个变量，并且不要清共享缓存：冷缓存下载放在独立临时缓存目录（npm 用 `--cache` 指定，pip 用 `--cache-dir`，pnpm 用独立 store），暖缓存复用同一目录再装一次，比较哈希和耗时；实验结束后删除临时目录，原缓存保持可用。`npm cache verify`、`pnpm store status` 能反映各自缓存状态，`pip cache dir` 只显示缓存路径，不能当作缓存健康检查。",{"type":25,"children":132},[133],{"text":134,"type":29},"清缓存后哈希变了，且来源、版本与算法都没变时，说明缓存里的包与基准不符，但仍要排除镜像切换和上游重发；两次哈希都对但安装失败，问题在解压或权限，不在下载。",{"type":38,"level":39,"children":136},[137],{"text":138,"type":29},"依赖哈希不一致时检查来源并记录结果",{"type":38,"level":21,"children":140},[141],{"text":142,"type":29},"依次检查官方源、镜像源和 TLS 证书链",{"type":25,"children":144},[145],{"text":146,"type":29},"先换官方源复测，再按现象归因：",{"type":25,"children":148},[149],{"text":150,"type":29},"官方源校验仍不符时，先核实版本、校验算法和可信基准，再判断依赖发布是否异常。",{"type":25,"children":152},[153],{"text":154,"type":29},"官方源校验通过而镜像源失败时，检查镜像是否同步到相同版本。",{"type":25,"children":156},[157],{"text":158,"type":29},"两边都校验失败且伴随证书错误时，再检查证书链和代理是否重新签发证书。\n企业代理替换证书时，先把企业 CA 导入信任库再复测，不要直接关闭校验。",{"type":38,"level":21,"children":160},[161],{"text":162,"type":29},"记录依赖版本、校验值和下载来源",{"type":25,"children":164},[165],{"text":166,"type":29},"记录包名和版本、锁文件与下载文件的哈希、缓存是否命中，以及解压后的文件数和总大小。\n验收要求三层校验全过，且清缓存重下结果一致。安装影响到共享缓存或 CI 其他任务时，立即停止并恢复缓存目录。",{"type":25,"children":168},[169,171,176],{"text":170,"type":29},"安装或下载异常仍未定位时，可从",{"text":172,"type":29,"marks":173},"全球代理帮助中心",[174],{"href":175,"type":120},"https:\u002F\u002Fhelp.quanqiudaili.com\u002F",{"text":177,"type":29},"查找接入文档。",{"type":25,"children":179},[180],{"text":181,"type":29},"校验机制的官方说明：",{"type":183,"format":184,"children":185},"list","unordered",[186,194],{"type":187,"children":188},"list-item",[189],{"text":190,"type":29,"marks":191},"pip 哈希校验（`--require-hashes`）",[192],{"href":193,"type":120},"https:\u002F\u002Fpip.pypa.io\u002Fen\u002Fstable\u002Ftopics\u002Fsecure-installs\u002F",{"type":187,"children":195},[196],{"text":197,"type":29,"marks":198},"Go 模块校验（`go.sum` 与 `go mod verify`）",[199],{"href":200,"type":120},"https:\u002F\u002Fgo.dev\u002Fref\u002Fmod",{"type":38,"level":39,"children":202},[203],{"text":204,"type":29},"常见问题",{"type":38,"level":21,"children":206},[207],{"text":208,"type":29},"锁文件哈希和实际下载哈希不一致，先查什么？",{"type":25,"children":210},[211],{"text":212,"type":29},"先换官方源复测，区分镜像问题和链路改写；再确认是否启用了会替换内容的代理。",{"type":38,"level":21,"children":214},[215],{"text":216,"type":29},"代理断了以后继续下载，文件还能用吗？",{"type":25,"children":218},[219],{"text":220,"type":29},"不一定。大小正确不能证明内容完整；续传完成后按来源、版本和校验算法重新比对，不一致再区分缓存、镜像与上游变化。","",[223,353,477],{"source":6,"id":224,"documentId":225,"translationKey":225,"locale":9,"slug":226,"path":227,"_path":227,"title":228,"description":229,"excerpt":229,"image":230,"publishedAt":231,"updatedAt":232,"author":17,"tags":233,"featured":19,"sortOrder":20,"readingTime":39,"bodyType":22,"bodyBlocks":234,"bodyHtml":221},3987,"ehyrf4ygtsshhwkd0o87xat6","tls-certificate-compatibility-proxy-testing","\u002Fblog\u002Ftls-certificate-compatibility-proxy-testing","应用发布前，如何检查代理环境下的 TLS 证书兼容性","先分清直连、隧道转发和代理中间人三类链路，再逐级核对证书链、信任库位置与 SAN；本机正常而容器失败的，多为 CA 没进镜像。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_TLS_cover_ad09ec52a5.webp","2026-11-06T07:43:24.293Z","2026-11-06T07:43:24.278Z",[],[235,244,248,252,260,264,268,272,276,280,284,288,292,296,300,304,308,312,321,325,334,337,341,345,349],{"type":25,"children":236},[237,239,242],{"text":238,"type":29},"代理环境下的 TLS 问题，先要分清证书由谁签发：直连看目标证书，隧道转发看目标证书，代理中间人看代理自签 CA。",{"text":31,"type":29,"marks":240},[241],{"type":34},{"text":243,"type":29}," 本身不改变 TLS 握手，但企业代理或抓包工具会替换证书链，发布前必须把这条链路完整验一遍。",{"type":38,"level":39,"children":245},[246],{"text":247,"type":29},"先确认代理是否会替换目标站的 TLS 证书",{"type":25,"children":249},[250],{"text":251,"type":29},"直连或 HTTP CONNECT 隧道通常保留目标站点的证书，应检查证书链、有效期和 SAN（证书允许使用的域名）。如果企业代理会解密并重新签发 TLS 流量，客户端看到的是企业代理签发的站点证书；此时要确认该证书能连到受信任的企业 CA。先判断代理是否替换了证书，再确定检查对象。",{"type":25,"children":253},[254,256,259],{"text":255,"type":29},"核对代理协议与客户端接入方式时，可参考",{"text":116,"type":29,"marks":257},[258],{"href":119,"type":120},{"text":122,"type":29},{"type":38,"level":39,"children":261},[262],{"text":263,"type":29},"使用 OpenSSL 查看代理连接返回的证书链",{"type":25,"children":265},[266],{"text":267,"type":29},"```bash\nopenssl s_client -proxy proxy.example.com:8080 \\\n-connect target.example.com:443 \\\n-servername target.example.com -showcerts \\\n-verify_hostname target.example.com -verify_return_error \\\n-CAfile \u002Fpath\u002Fto\u002Fca-bundle.pem\n```",{"type":25,"children":269},[270],{"text":271,"type":29},"查看输出中的 `issuer`、有效期和 SAN，并重点看两件事：证书链能否构建到受信锚、主机名是否匹配。服务端通常只提供叶证书和中间证书，不要求它回传根证书；根证书应该来自你信任的本地信任库（`-CAfile` 或 `-CApath`），而不是从连接里“捡”到一个就信。验收看退出码和验证输出（`Verify return code`），不要只看“连接成功”；最后仍在真实应用运行时或容器里做一次正负对照。",{"type":25,"children":273},[274],{"text":275,"type":29},"`-proxy` 参数需要 OpenSSL 1.1.0 或更高版本，且默认只支持 HTTP CONNECT；SOCKS5 场景改用支持该协议的工具（如 curl 的 `--proxy socks5h:\u002F\u002F`）或对应的客户端验证。运行 `openssl version` 可先检查本机版本。",{"type":38,"level":39,"children":277},[278],{"text":279,"type":29},"检查系统、运行时和容器使用的证书信任库",{"type":25,"children":281},[282],{"text":283,"type":29},"信任库位置取决于应用使用的运行时：Linux 系统证书通常位于 `\u002Fetc\u002Fssl\u002Fcerts`，Java 使用自己的 `cacerts`，Node 可通过 `NODE_EXTRA_CA_CERTS` 指定额外 CA，Python 的 `requests` 常使用 `certifi`。容器还要单独检查镜像内的证书。本机正常而容器失败时，先比较两边实际加载的 CA。",{"type":38,"level":39,"children":285},[286],{"text":287,"type":29},"根据 TLS 错误定位证书链和主机名问题",{"type":25,"children":289},[290],{"text":291,"type":29},"出现 `unable to get local issuer certificate` 时，先检查证书链是否缺少中间 CA；出现 `self signed certificate` 时，确认它是否为预期的企业 CA 或测试证书。`hostname mismatch` 通常表示证书 SAN 不包含目标域名；`protocol version` 或 `cipher mismatch` 则需要核对客户端与服务端支持的 TLS 版本和加密套件。",{"type":38,"level":39,"children":293},[294],{"text":295,"type":29},"发布前检查证书有效期、信任链和轮换结果",{"type":38,"level":21,"children":297},[298],{"text":299,"type":29},"在预发布环境验证证书更新和轮换",{"type":25,"children":301},[302],{"text":303,"type":29},"发布前记录证书到期时间，证书轮换后复测一次；灰度环境的信任库要和生产一致，否则灰度通过、生产失败。",{"type":38,"level":21,"children":305},[306],{"text":307,"type":29},"记录证书签发者、有效期和信任库位置",{"type":25,"children":309},[310],{"text":311,"type":29},"发布前记录目标域名和端口、证书签发者与到期时间、信任库位置，以及代理是否会重新签发证书。\n检查清单四项：链能构建到受信锚、CA 在信任库、主机名匹配 SAN、证书未过期。任一项不满足就不能发布；发现证书替换影响生产流量时，立即回滚配置。",{"type":25,"children":313},[314,316,319],{"text":315,"type":29},"证书链异常仍无法归因时，可从",{"text":172,"type":29,"marks":317},[318],{"href":175,"type":120},{"text":320,"type":29},"查找对应接入文档。",{"type":25,"children":322},[323],{"text":324,"type":29},"OpenSSL 参数以手册为准：",{"type":183,"format":184,"children":326},[327],{"type":187,"children":328},[329],{"text":330,"type":29,"marks":331},"`openssl s_client` 手册（`-proxy`、`-verify_hostname`、`-verify_return_error`）",[332],{"href":333,"type":120},"https:\u002F\u002Fdocs.openssl.org\u002F3.5\u002Fman1\u002Fopenssl-s_client\u002F",{"type":38,"level":39,"children":335},[336],{"text":204,"type":29},{"type":38,"level":21,"children":338},[339],{"text":340,"type":29},"代理环境下证书报错一定是代理问题吗？",{"type":25,"children":342},[343],{"text":344,"type":29},"不一定。先看证书链和信任库，主机名不符或 CA 缺失更常见。",{"type":38,"level":21,"children":346},[347],{"text":348,"type":29},"为什么本机正常、容器里失败？",{"type":25,"children":350},[351],{"text":352,"type":29},"容器镜像没有导入同一个 CA，信任库不一致。",{"source":6,"id":354,"documentId":355,"translationKey":355,"locale":9,"slug":356,"path":357,"_path":357,"title":358,"description":359,"excerpt":359,"image":360,"publishedAt":361,"updatedAt":362,"author":17,"tags":363,"featured":19,"sortOrder":20,"readingTime":39,"bodyType":22,"bodyBlocks":364,"bodyHtml":221},3986,"g5ee4zs0pa8hyuc307nk5nwf","proxy-error-handling-mock-testing","\u002Fblog\u002Fproxy-error-handling-mock-testing","如何在不依赖真实代理服务时测试应用的代理错误处理","用可注入的代理桩和故障矩阵覆盖超时、拒绝、认证失败，在受控环境验证重试、退避与降级；不接真实代理，也不记录任何真实凭据。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_cover_5ce09c130c.webp","2026-11-06T07:42:03.722Z","2026-11-06T07:42:03.708Z",[],[365,374,378,382,386,390,394,398,402,406,410,421,425,429,438,442,458,461,465,469,473],{"type":25,"children":366},[367,369,372],{"text":368,"type":29},"代理错误处理最适合用本地 mock 验证。407、超时、连接重置、TLS 失败、慢响应、半关闭六类故障都能稳定复现，测试不再依赖服务商侧的偶发故障。",{"text":31,"type":29,"marks":370},[371],{"type":34},{"text":373,"type":29}," 的真实链路不可控，mock 的价值就是把“偶发”变成“可重复”，但结论只对应用逻辑成立。",{"type":38,"level":39,"children":375},[376],{"text":377,"type":29},"代理错误测试需要覆盖的六种故障",{"type":25,"children":379},[380],{"text":381,"type":29},"可先覆盖六种常见故障：让 mock 返回带 `Proxy-Authenticate` 的 407，检查客户端是否重试或报告认证错误；延迟超过客户端超时时，检查超时处理；连接重置时，检查中断后的动作；TLS 负例一次只改一个变量（未受信 CA、可信 CA 但 SAN 不对、证书过期），并保持校验开启，看客户端实际报什么错；分段延迟发送时，记录首字节和完整响应耗时；测“响应不完整”时，用声明了 `Content-Length` 却提前 EOF、或缺少 chunked 终止块的响应做负例，完整的 close-delimited 响应只作正常对照——单纯关闭写方向并不等于响应不完整。之后再按应用实际支持的错误分支补充测试。\n矩阵按应用实际支持的错误分支建立，上表是起步集合，可以补代理 DNS 失败、认证挑战格式异常和重试上限三类用例。矩阵未覆盖的分支，不会被这一组测试验证。",{"type":38,"level":39,"children":383},[384],{"text":385,"type":29},"如何搭建可重复触发故障的 mock 代理",{"type":25,"children":387},[388],{"text":389,"type":29},"mitmproxy、toxiproxy 或自建 TCP 服务都可以用于 mock，但注入点要和故障所在层对应。407 需要能处理 CONNECT 并返回 `Proxy-Authenticate` 的受控代理；TCP 延迟和连接重置可在传输层注入；SOCKS 认证错误则要按 SOCKS 协议构造，不能用 HTTP 的 407 代替。记录工具、客户端版本、触发步骤和清理方法，其他人才能复现。",{"type":38,"level":39,"children":391},[392],{"text":393,"type":29},"除了错误码，还要验证应用如何处理故障",{"type":25,"children":395},[396],{"text":397,"type":29},"收到 407 只说明应用识别到了代理认证错误。还要检查重试次数和间隔、熔断或降级是否符合预期，以及日志是否隐藏凭据。407 和 401 要分开判断：前者由代理要求认证，后者由目标服务要求认证。",{"type":25,"children":399},[400],{"text":401,"type":29},"407 和 401 必须分开断言：`Proxy-Authenticate` 是代理要求认证，`WWW-Authenticate` 是目标服务要求认证。混在一起，会把代理认证失败记成应用登录失败。",{"type":38,"level":39,"children":403},[404],{"text":405,"type":29},"避免 mock 测试漏掉真实故障分支",{"type":25,"children":407},[408],{"text":409,"type":29},"要触发客户端超时，mock 延迟必须超过客户端配置的超时值；要测试请求中断后的处理，应在连接建立后再重置。mock 结果只说明应用对模拟故障的处理方式，不能直接推断真实代理链路表现。",{"type":25,"children":411},[412,414,419],{"text":413,"type":29},"mock 通过后若要转入真实环境验证，可按",{"text":415,"type":29,"marks":416},"全球代理使用流程",[417],{"href":418,"type":120},"https:\u002F\u002Fhelp.quanqiudaili.com\u002Fdocs\u002FProcess",{"text":420,"type":29},"依次核对产品、参数和接入步骤。",{"type":38,"level":39,"children":422},[423],{"text":424,"type":29},"记录 mock 故障参数和应用处理结果",{"type":25,"children":426},[427],{"text":428,"type":29},"每个用例记录故障类型、注入参数、期望动作、实际结果，以及日志是否隐藏凭据。\n用例边界是应用逻辑，不覆盖真实服务商的 SLA 和地区行为。出现真实凭据进入 mock 日志、或测试影响到共享环境时，立即停止并清理。",{"type":25,"children":430},[431,433,436],{"text":432,"type":29},"开始真实环境验证前，可用",{"text":116,"type":29,"marks":434},[435],{"href":119,"type":120},{"text":437,"type":29},"核对协议、地址和认证参数。",{"type":25,"children":439},[440],{"text":441,"type":29},"故障注入工具与协议定义：",{"type":183,"format":184,"children":443},[444,451],{"type":187,"children":445},[446],{"text":447,"type":29,"marks":448},"toxiproxy（TCP 延迟、重置、带宽限制）",[449],{"href":450,"type":120},"https:\u002F\u002Fgithub.com\u002FShopify\u002Ftoxiproxy",{"type":187,"children":452},[453],{"text":454,"type":29,"marks":455},"RFC 9110《HTTP Semantics》（407 与 `Proxy-Authenticate`）",[456],{"href":457,"type":120},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9110.html",{"type":38,"level":39,"children":459},[460],{"text":204,"type":29},{"type":38,"level":21,"children":462},[463],{"text":464,"type":29},"mock 代理能替代真实代理测试吗？",{"type":25,"children":466},[467],{"text":468,"type":29},"不能。它验证应用逻辑，不验证真实链路的稳定性和地区行为。",{"type":38,"level":21,"children":470},[471],{"text":472,"type":29},"407 和 401 有什么区别？",{"type":25,"children":474},[475],{"text":476,"type":29},"407 是代理要求认证，401 是目标服务要求认证。",{"source":6,"id":478,"documentId":479,"translationKey":479,"locale":9,"slug":480,"path":481,"_path":481,"title":482,"description":483,"excerpt":483,"image":484,"publishedAt":485,"updatedAt":486,"author":17,"tags":487,"featured":19,"sortOrder":20,"readingTime":39,"bodyType":22,"bodyBlocks":488,"bodyHtml":221},3985,"bpamp8c4gnpz3p9kslssa97y","ci-runner-proxy-build-impact-testing","\u002Fblog\u002Fci-runner-proxy-build-impact-testing","如何在 CI Runner 中验证代理不会影响构建步骤","在 Runner 内固定镜像、构建输入与测试时段，用出口 IP、DNS、TLS 和依赖清单作为证据，区分代理影响与构建环境波动；产物哈希只在构建可复现时才作对照。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_CI_Runner_cover_023a325e36.webp","2026-11-06T07:41:47.066Z","2026-11-06T07:41:47.049Z",[],[489,493,497,501,505,509,518,522,526,530,534,538,542,546,555,559,575,578,582,586,590],{"type":25,"children":490},[491],{"text":492,"type":29},"判断代理是否影响 CI，不能只看最终构建是否成功。应按实际流程检查代码拉取、依赖安装、单元测试、构建和产物上传。代理配置可能来自环境变量、包管理器或容器后台服务；配置不一致时，本地命令与流水线可能表现不同。",{"type":38,"level":39,"children":494},[495],{"text":496,"type":29},"如何判断代理没有影响 CI 构建",{"type":25,"children":498},[499],{"text":500,"type":29},"按顺序检查代码是否拉取到相同 commit、依赖校验是否通过、单元测试结果是否与基线一致。构建可复现时比较产物哈希；否则比较关键文件和依赖清单。上传环节要确认远端文件实际存在，并在支持时核对摘要或完整性校验。各阶段记录退出码和耗时；确需记录出口 IP 时，应使用受控日志并隐藏代理凭据。",{"type":38,"level":39,"children":502},[503],{"text":504,"type":29},"检查 CI 环境变量、包管理器和容器的代理配置",{"type":25,"children":506},[507],{"text":508,"type":29},"先检查构建进程是否读取 `HTTP_PROXY` 和 `HTTPS_PROXY`，再确认 `NO_PROXY` 中哪些地址会绕过代理。npm、pip 和 Maven 也可能分别读取 `.npmrc`、`pip.conf` 或 `settings.xml`；容器拉取镜像则由容器后台服务的配置决定。不要只凭宿主机环境变量判断代理已经生效。",{"type":25,"children":510},[511,513,516],{"text":512,"type":29},"配置入口和协议参数可对照",{"text":116,"type":29,"marks":514},[515],{"href":119,"type":120},{"text":517,"type":29},"逐项核实。",{"type":38,"level":39,"children":519},[520],{"text":521,"type":29},"对比启用代理和不启用代理时的构建结果",{"type":25,"children":523},[524],{"text":525,"type":29},"在相同 commit、Runner 镜像、依赖来源和资源规格下，分别运行启用代理与不启用代理的任务。冷缓存和暖缓存应分开比较，并使用隔离的缓存目录；每组可重复运行并保留原始结果。除代理开关外，其他条件尽量保持一致，便于判断差异来源。",{"type":38,"level":39,"children":527},[528],{"text":529,"type":29},"区分正常的耗时变化与构建产物差异",{"type":25,"children":531},[532],{"text":533,"type":29},"代理会让下载耗时发生变化，但不能预设“代理一定更慢”。判断是否影响构建，用各阶段耗时分布和事前设定的预算，不用单次耗时下结论；产物对照的前提是构建可复现、非确定性元数据已规范化；做不到时改比依赖清单、测试结果、关键文件和构建日志，不能仅凭整体哈希变化判定代理造成回归。",{"type":25,"children":535},[536],{"text":537,"type":29},"两类误判最常见：`NO_PROXY` 漏配，内部制品库被送进代理，出现 407 或超时；缓存掩盖失败，上一次的缓存让本次跳过了真实下载，清缓存复跑才暴露问题。",{"type":38,"level":39,"children":539},[540],{"text":541,"type":29},"记录 CI 代理测试结果并设定验收条件",{"type":25,"children":543},[544],{"text":545,"type":29},"记录 Runner 镜像、commit、实际生效的代理配置和各阶段结果，并注明缓存命中情况。被缓存跳过的步骤应标为未覆盖，必要时单独补跑。所有相关阶段通过后，再依据构建是否可复现判断产物差异。若影响其他流水线、日志出现凭据或耗时超过预算，应停止并回滚配置。",{"type":25,"children":547},[548,550,553],{"text":549,"type":29},"CI 中出现连接失败时，可从",{"text":172,"type":29,"marks":551},[552],{"href":175,"type":120},{"text":554,"type":29},"查找官方接入说明。",{"type":25,"children":556},[557],{"text":558,"type":29},"相关机制说明：",{"type":183,"format":184,"children":560},[561,568],{"type":187,"children":562},[563],{"text":564,"type":29,"marks":565},"`npm ci` 的安装与校验行为",[566],{"href":567,"type":120},"https:\u002F\u002Fdocs.npmjs.com\u002Fcli\u002Fv10\u002Fcommands\u002Fnpm-ci",{"type":187,"children":569},[570],{"text":571,"type":29,"marks":572},"GitHub Actions 依赖缓存",[573],{"href":574,"type":120},"https:\u002F\u002Fdocs.github.com\u002Factions\u002Fusing-workflows\u002Fcaching-dependencies-to-speed-up-workflows",{"type":38,"level":39,"children":576},[577],{"text":204,"type":29},{"type":38,"level":21,"children":579},[580],{"text":581,"type":29},"CI 里设了 HTTP_PROXY 为什么还是不走代理？",{"type":25,"children":583},[584],{"text":585,"type":29},"可能被 NO_PROXY 覆盖，或包管理器有独立配置，以实际生效的配置为准。",{"type":38,"level":21,"children":587},[588],{"text":589,"type":29},"构建成功就说明代理没影响吗？",{"type":25,"children":591},[592],{"text":593,"type":29},"不一定。缓存可能掩盖下载失败，需要清缓存复跑并比对产物。",[595],{"source":6,"id":7,"documentId":8,"translationKey":8,"locale":9,"slug":10,"path":11,"_path":11,"title":12,"description":13,"excerpt":13,"image":14,"publishedAt":15,"updatedAt":16,"author":17,"tags":596,"featured":19,"sortOrder":20,"readingTime":21,"bodyType":22,"bodyBlocks":597,"bodyHtml":221},[],[598,605,608,611,617,623,629,635,641,644,647,650,653,656,659,666,669,672,675,678,681,684,687,690,693,696,699,706,709,721,724,727,730,733],{"type":25,"children":599},[600,601,604],{"text":28,"type":29},{"text":31,"type":29,"marks":602},[603],{"type":34},{"text":36,"type":29},{"type":38,"level":39,"children":606},[607],{"text":42,"type":29},{"type":25,"children":609},[610],{"text":46,"type":29},{"type":25,"children":612},[613,616],{"text":50,"type":29,"marks":614},[615],{"type":34},{"text":54,"type":29},{"type":25,"children":618},[619,622],{"text":58,"type":29,"marks":620},[621],{"type":34},{"text":62,"type":29},{"type":25,"children":624},[625,628],{"text":66,"type":29,"marks":626},[627],{"type":34},{"text":70,"type":29},{"type":25,"children":630},[631,634],{"text":74,"type":29,"marks":632},[633],{"type":34},{"text":78,"type":29},{"type":25,"children":636},[637,640],{"text":82,"type":29,"marks":638},[639],{"type":34},{"text":86,"type":29},{"type":38,"level":39,"children":642},[643],{"text":90,"type":29},{"type":25,"children":645},[646],{"text":94,"type":29},{"type":25,"children":648},[649],{"text":98,"type":29},{"type":38,"level":39,"children":651},[652],{"text":102,"type":29},{"type":25,"children":654},[655],{"text":106,"type":29},{"type":25,"children":657},[658],{"text":110,"type":29},{"type":25,"children":660},[661,662,665],{"text":114,"type":29},{"text":116,"type":29,"marks":663},[664],{"href":119,"type":120},{"text":122,"type":29},{"type":38,"level":39,"children":667},[668],{"text":126,"type":29},{"type":25,"children":670},[671],{"text":130,"type":29},{"type":25,"children":673},[674],{"text":134,"type":29},{"type":38,"level":39,"children":676},[677],{"text":138,"type":29},{"type":38,"level":21,"children":679},[680],{"text":142,"type":29},{"type":25,"children":682},[683],{"text":146,"type":29},{"type":25,"children":685},[686],{"text":150,"type":29},{"type":25,"children":688},[689],{"text":154,"type":29},{"type":25,"children":691},[692],{"text":158,"type":29},{"type":38,"level":21,"children":694},[695],{"text":162,"type":29},{"type":25,"children":697},[698],{"text":166,"type":29},{"type":25,"children":700},[701,702,705],{"text":170,"type":29},{"text":172,"type":29,"marks":703},[704],{"href":175,"type":120},{"text":177,"type":29},{"type":25,"children":707},[708],{"text":181,"type":29},{"type":183,"format":184,"children":710},[711,716],{"type":187,"children":712},[713],{"text":190,"type":29,"marks":714},[715],{"href":193,"type":120},{"type":187,"children":717},[718],{"text":197,"type":29,"marks":719},[720],{"href":200,"type":120},{"type":38,"level":39,"children":722},[723],{"text":204,"type":29},{"type":38,"level":21,"children":725},[726],{"text":208,"type":29},{"type":25,"children":728},[729],{"text":212,"type":29},{"type":38,"level":21,"children":731},[732],{"text":216,"type":29},{"type":25,"children":734},[735],{"text":220,"type":29},null,[],[]]