
页面里的 JavaScript 或 CSS 请求返回了 200,浏览器却拒绝使用它,Console 提示无法找到匹配的 integrity 摘要。遇到这种情况,先保留失败页面和资源副本,不要直接删除 integrity 属性。浏览器可能确实收到了与页面声明不同的文件。
Subresource Integrity(SRI,子资源完整性)通过页面中的预期哈希检查下载资源。本文聚焦 CDN 环境下 JS/CSS 加载失败的定位:文件是否变了、跨域访问是否满足条件,以及 HTML 与资源版本是否配套。示例面向可管理网站构建和 CDN 配置的人员,命令需替换地址,不代表生产环境实测结果。
先确认报错属于哪一类
查看 Console 中第一条相关错误,再到 Network 核对完整 URL、最终响应与内容类型。
| 现象 | 优先检查 |
|---|---|
| 提示计算出的摘要不匹配 | 文件内容与 integrity 中的哈希 |
| 提示跨域或 CORS 检查失败 | crossorigin 属性与资源响应的 CORS 头 |
| 返回 HTML 或登录页面 | 回退路由、鉴权、WAF 与重定向 |
| 部分用户失败、部分用户正常 | 不同 HTML 版本、节点缓存与源站实例 |
| 报 CSP 或 MIME 拒绝执行 | 对应安全策略或类型配置,勿全归因于 SRI |
200 只说明请求得到成功状态,无法证明它是所需的脚本。将错误页包装为 200、将不存在的文件回退到首页,都可能让哈希不同。
SRI 校验也不能替代 CSP。一个文件通过哈希校验后,仍可能被页面的 CSP 阻止。应按实际报错逐项处理。[1]
保存原始证据,再比较 CDN 与源站文件
记录失败页面实际使用的 script 或 link 元素,包括 URL、integrity 与 crossorigin。不要只看仓库里最新的模板,因为用户收到的可能是旧 HTML。
下面用 GET 保存响应,--compressed 请求 curl 支持的压缩格式并自动解压:
curl --fail --location --compressed --silent --show-error \ --dump-header edge-headers.txt --output edge-app.js \ https://static.example.net/assets/app.a81d9f.js
先检查退出状态、响应头与文件内容。--fail 能帮助识别 HTTP 错误,但对伪装成 200 的错误页仍需人工判断。--location 会跟随跳转,保存的头文件可能包含多段响应,需检查最终响应及跳转链。
若有获准的源站访问路径,可以保持同一 URL 主机名,定向源站比较:
curl --fail --location --compressed --silent --show-error \ --resolve static.example.net:443:203.0.113.10 \ --dump-header origin-headers.txt --output origin-app.js \ https://static.example.net/assets/app.a81d9f.js
示例 IP 仅用于文档。--resolve 保留 URL 中的 Host、TLS SNI 与证书校验名称。源站仅接受 CDN 网络时,应使用批准的运维入口,勿临时开放公网访问或用 -k 跳过证书验证。若请求重定向到其他域名,上述解析覆盖不会自动应用于新域名,需单独核对。
curl 不执行浏览器的 CORS 和 SRI 检查,下载成功不能作为浏览器一定可加载的结论。
对最终资源内容计算正确格式的哈希
在 Linux、macOS 或安装了 OpenSSL 的环境中,可以对已核实的文件计算 SHA-384:
openssl dgst -sha384 -binary edge-app.js | openssl base64 -A
integrity 使用算法前缀加 Base64 摘要,例如 sha384- 后接命令输出。不要直接复制十六进制的 sha384sum 输出,也不要对整个 HTML 或文件名计算摘要。[1]
Windows 上可用 Python 对文件字节计算同样结果:
python -c "import hashlib,base64; print('sha384-'+base64.b64encode(hashlib.sha384(open('edge-app.js','rb').read()).digest()).decode())"这里应比较浏览器获得的、经过 HTTP 内容编码解码后的资源字节。正常 gzip 或 Brotli 压缩并在传输后解压,通常不会改变该内容;把压缩包本身拿来计算哈希则会得到不同结果。CDN 压缩配置与 Content-Encoding 若不匹配,还可能先触发解码错误,需要另行修复。
将结果与失败页面声明的摘要、可信构建产物的摘要逐一对比。不要直接把未知线上文件算出的值填回页面:如果文件遭到篡改,这样做会将异常内容授权。预期值应来自可信构建与发布流程。
支持的摘要算法包括 SHA-256、SHA-384 和 SHA-512。属性包含多种算法时,浏览器按最强的受支持算法处理;不能把附加一个弱算法值当成兼容性修复。[1]
跨域 SRI 要同时满足 CORS
页面在 www.example.com,资源在 static.example.net,属于跨域。常见公共静态资源写法如下,哈希必须替换为可信产物的实际值:
<script src="https://static.example.net/assets/app.a81d9f.js" integrity="sha384-REPLACE_WITH_REAL_BASE64_DIGEST" crossorigin="anonymous"></script> <link rel="stylesheet" href="https://static.example.net/assets/site.b72e10.css" integrity="sha384-REPLACE_WITH_REAL_BASE64_DIGEST" crossorigin="anonymous">
跨域 SRI 资源需要通过 CORS 检查。crossorigin="anonymous" 配合允许该页面来源的资源响应,是公共资源常见配置。[1][2]
完全公开且不依赖凭证的资源,可以按业务条件评估 Access-Control-Allow-Origin: *。若按请求 Origin 动态返回具体允许来源,应设置合适的 Vary: Origin,并确认 CDN 缓存确实按需要区分响应。不要简单回显任意 Origin 来绕过访问控制。
anonymous 不会向跨域资源发送凭证。若资源依赖 Cookie,可能因此得到登录页或拒绝响应。公共构建产物通常应与登录态解耦;确需带凭证时,需要另行设计严格 CORS 策略,不能把通配来源与凭证请求拼在一起。
可用下面的请求检查资源返回的头部:
curl -sS -L -D - -o /dev/null \ -H 'Origin: https://www.example.com' \ https://static.example.net/assets/app.a81d9f.js
它只能帮助观察响应,不能代替真实浏览器验证。普通的跨域资源加载也不意味着一定产生 OPTIONS 预检,勿把“没有预检”当成故障证据。
查明是哪一步改变了文件或配错版本
如果可信构建产物与源站相同、CDN 副本不同,检查边缘压缩以外的内容变换:自动压缩代码、脚本注入、优化重写等。SRI 对内容变化敏感;即使改动只涉及空白或注释,摘要也会变化。应让构建产物在生成哈希后保持字节稳定,或建立能够正确同步哈希的可信发布链路。
如果不同源站副本返回不同文件,先修复部署一致性。若同一个 URL 被不断覆盖,缓存新旧副本会让问题更难追踪。使用带内容指纹的 URL,并避免修改已发布 URL 对应的内容。
还要检查这些组合:
新 HTML 携带新哈希,却引用旧资源 URL。
旧 HTML 保留旧哈希,但该 URL 已被覆盖为新文件。
构建后的模板重新处理代码,导致哈希计算早于最后一次内容变更。
CDN 或浏览器、Service Worker 保留另一版 HTML。
哈希一致但浏览器仍失败时,应回到该浏览器实际请求与策略核对,确认比较的是同一 URL、同一变体,而非本地另一个文件。
按产物与页面配套发布,保留可回滚版本
修改前保留当前 HTML、构建产物、资源清单及 CDN 规则。先上传新指纹资源,验证它们可访问且内容与可信产物相同,再发布引用对应 URL 和哈希的 HTML。旧资源应保留与缓存和用户访问情况匹配的过渡期,供旧页面与回滚使用。
需要刷新时,先限定受影响的 HTML 或资源对象,确认缓存键与实际 URL 一致。大范围刷新可能增加源站负载,宜避开高峰并保留停止扩散的方案。
验收时同时检查 JavaScript 和 CSS:页面 DOM 中的 URL、integrity、crossorigin 正确;浏览器 CORS 与 SRI 检查通过;动态功能和样式正常;新会话及原有标签页均按预期工作。
若新版本失败,应恢复上一版 HTML 与配套资源清单,再验证用户实际收到的版本。删掉 integrity、放开所有 CORS 来源或降低 CSP,都不应作为默认回滚方式。
最终在工单中留下失败页面版本、资源 URL、预期与实际摘要,以及修复后的浏览器结果。这样才能明确这次问题来自文件变化、跨域条件还是发布错配。
参考资料
资料核验日期:2026 年 10 月 22 日。配置示例需结合实际网站与 CDN 调整。