integrity校验失败不会触发onerror,而是静默丢弃;必须搭配crossorigin="anonymous"才生效;可靠fallback需用fetch主动探测CDN资源状态后动态加载本地样式。

integrity 校验失败时不会触发 onerror
这是最容易踩的坑:integrity 失败是静默丢弃,onerror 完全不会被调用。浏览器只在 Console 里埋一条 Failed to find a valid digest in the 'integrity' attribute warning(默认可能被过滤),页面照样渲染,但样式就没了——你根本不知道用户看到的是裸 HTML。
原因很直接:SRI 校验发生在资源加载完成之后、解析之前;而 onerror 只响应网络层失败(404、CORS 拒绝、连接中断等)。只要 CDN 返回了 HTTP 200 + text/css,哪怕内容被篡改或哈希算错,onerror 就不触发。
CDN 回源失败 ≠ integrity 失效,但两者常同时发生
回源失败(比如源站宕机、CDN 节点无法连通后端)通常导致 CDN 返回 502/503 或兜底 HTML 错误页,此时 MIME 类型变成 text/html 或 text/plain,浏览器报错 Refused to apply style from 'xxx' because its MIME type ('text/plain') is not a supported stylesheet MIME type——这属于加载失败,onerror 会生效。
但要注意:如果 CDN 配了“错误页缓存”或“兜底静态页”,它可能返回一个看似正常的 200 HTML 页面,这时 onerror 不触发,integrity 也因内容非 CSS 而校验失败,双重静默失效。
立即学习“前端免费学习笔记(深入)”;
- 检查 Network 面板里该请求的 Response Headers,确认
Content-Type: text/css - 手动在浏览器地址栏打开
href值,看是否真返回 CSS 内容(不是 404/502 页面) - 回源失败时,优先排查 CDN 控制台的回源日志和健康检查状态,而不是只盯着 HTML
必须搭配 crossorigin 才能让 integrity 生效
integrity 单独写等于没写。它必须和 crossorigin="anonymous" 成对出现,否则浏览器跳过校验——连 warning 都不报,资源照常加载。
常见错误写法:
-
<link rel="stylesheet" href="..." integrity="sha384-xxx">—— 缺crossorigin -
<link rel="stylesheet" href="..." integrity="sha384-xxx" crossorigin>——crossorigin无值,非法 -
<link rel="stylesheet" href="..." integrity="sha384-xxx" crossorigin="use-credentials">—— CDN 未返回Access-Control-Allow-Credentials: true,校验失败
正确写法只有一种:<link rel="stylesheet" href="..." integrity="sha384-xxx" crossorigin="anonymous">
真正可靠的 fallback 必须绕过 integrity 的静默机制
想让 CDN 失效时一定切本地,不能依赖 onerror 或 integrity,得用主动探测:
- 用
fetch()请求 CDN URL,检查response.status === 200且response.headers.get('content-type')?.includes('text/css') - 加 3 秒超时,避免阻塞渲染
- 探测失败后,动态插入本地
<link rel="stylesheet">,路径必须是服务器可访问的绝对路径(如/css/bootstrap.min.css) - 不要指望 SRI 自动 fallback,它只负责“拦住坏资源”,不负责“补上好资源”
关键细节:探测用的 fetch() 不需要 integrity 或 crossorigin,它只是 HTTP 探针;真正的样式加载仍走带 SRI 的 <link>,二者职责分离。



















