
网站刚更新,首页却变成没有样式的文字,按钮失效,或者只有部分访客遇到白屏。此时重启服务或清空全部缓存未必有效:页面可能引用了还没上传的 CSS,也可能继续使用已经被删掉的旧 JavaScript。
先找到一条实际失败的资源请求,核对它的 URL、状态码、响应内容和引用来源,再判断缺的是文件、正确版本还是正确响应。 页面异常不一定由缓存引起;一次返回 200 的请求也可能拿到 HTML 错误页。
本文面向采用 Nginx、CDN 和构建型前端的网站,也涵盖 WordPress 主题或优化插件生成资源的常见问题。命令使用 Linux 与 curl,域名、资源名和路径为示例。发布变更应先在测试环境验证,保留上一版文件、配置和必要的数据备份。
从浏览器找出第一条异常请求
打开开发者工具的 Network 面板,保留日志后重新访问出现问题的页面。筛选 CSS、JavaScript、字体或图片,查看失败请求的完整 URL、发起者、状态、Content-Type 和响应内容。
不要只截图 Console 最后一条异常:一个入口脚本加载失败,可能引出大量后续报错。优先定位最早的网络失败,并记录发生时间、入口页面、浏览器与是否登录。导出 HAR 前需要清除 Cookie、令牌和个人信息。
| 观察结果 | 优先检查 |
|---|---|
| CSS 或 JS 返回 404 | 文件是否部署、路径大小写、引用版本、CDN 负缓存 |
| 返回 200,但内容是 HTML | SPA 回退、登录重定向、统一错误页或错误缓存 |
| 403 或安全拦截页 | 资源访问规则、防盗链、鉴权与 WAF |
| MIME、CSP、SRI 或混合内容报错 | Content-Type、安全策略、完整性哈希与协议 |
| 资源均加载成功,样式仍异常 | CSS 覆盖、加载顺序、构建结果与业务代码 |
浏览器禁用缓存后正常,只能说明缓存相关路径值得调查,不能直接证明 CDN 出错。Service Worker、内存缓存和磁盘缓存各有自己的行为,开发者工具的设置也不是所有缓存层的总开关。
检查真实 GET 响应,不只看状态码
对可安全读取的公开资源进行一次检查:
curl --connect-timeout 3 --max-time 10 -sS \
-D asset-headers.txt -o asset-body.txt \
https://example.com/assets/app.ABC123.css
将 URL 替换为浏览器实际请求,不要自己猜一个“差不多”的资源名。查看响应头的 Content-Type、Cache-Control、Age、ETag、Location,以及产品提供的缓存命中信息。响应头能提供线索,但字段缺失或存在都不能单独证明源站文件状态。
CSS 应返回正确的 CSS 内容和适当类型,例如 text/css。JavaScript 同样需要与浏览器加载方式相匹配的类型;启用严格 MIME 检查时,类型错误可能直接阻止加载。[2] 若内容以 HTML 开头,应查清是谁返回了页面,而不是通过修改 MIME 类型把错误内容伪装成脚本。
默认 curl 不会跟随重定向,可先观察 3xx 与 Location;只有确认跳转目标与安全边界后才决定是否跟随。HEAD 与 GET 可能由不同规则处理,因此不能只用 HEAD 成功来判断浏览器请求正常。
404 先对文件与引用,别立即改回退规则
核对发布产物中是否存在被请求的文件,路径大小写是否一致,站点是否部署到子目录,以及构建工具的 base 或 public path 是否正确。Linux 文件系统通常区分大小写,本地开发环境正常不代表上线后路径完全匹配。
还要检查 CSS 内的字体和图片相对路径:它们通常相对于样式表自身 URL 解析,不是相对于页面地址。只验证入口 CSS 存在,可能漏掉其引用的二级资源。
Nginx 的 root、alias、location 与 try_files 会影响 URL 到文件的映射。[3] SPA 常把未知路由回退到 index.html,但静态资源缺失时也返回 index.html,会造成“状态 200、脚本解析失败”。
如果部署结构确实是 root 下的 assets 目录,可评估给该目录明确的失败行为:
# 示例,放在对应 server 中;必须结合现有 location 规则验证
location /assets/ {
try_files $uri =404;
}
这只是示意,不适用于所有 alias、正则 location 或上游代理配置。它也可能改变原有鉴权、缓存头或访问日志继承效果。修改前检查实际有效配置,保留原安全规则,执行 nginx -t 后按部署方式重载。不要通过把所有 404 都转成首页掩盖缺文件。
分清浏览器、CDN 与页面缓存保存了什么
最常见的错配有两种:新页面已经上线,新资源还未到位;旧页面仍在缓存,旧资源却已经删除。刷新资源缓存无法自动修复页面里的旧 URL。
对照入口 HTML 中的引用、构建清单与服务器上的资源集合,确认它们来自同一次发布。记录异常用户实际拿到的页面版本,不能只看自己的管理端页面。
HTTP 缓存中,no-cache 允许存储,但要求复用前验证;no-store 用于要求不要存储,二者含义不同。[1] 页面使用 no-cache,也不代表旧页面在部署瞬间从所有地方消失,更不能因此马上删除旧资源。
对内容指纹命名的静态文件,可以在确定 URL 永不复用、内容不变后评估较长缓存与 immutable;对固定文件名反复覆盖的资源,不应照搬同一策略。HTML、登录页面和含个人数据的响应还需考虑验证与私有性,不能全站统一长缓存。
CDN 可能缓存 404,也可能按自定义规则忽略源站头部。查询参数能否区分版本取决于缓存键设置;随手加 ?v=2 不保证刷新所有缓存。若确认存在错误或负缓存,应针对具体 URL、相关页面及平台规则执行刷新,并观察源站是否已经返回正确内容。
不要在缺文件尚未补齐时全站刷新。这样可能把原本还能使用的缓存页面换成错误页面,或突然增加回源压力。
发布顺序需要同时照顾新页面与旧页面
更稳妥的静态资源发布通常遵循以下步骤:
- 从同一构建产物上传新版本资源,核对目标位置与完整性。
- 在源站及必要的分发路径确认关键资源可读取、类型正确。
- 切换引用这些资源的页面或发布入口,再验证正常业务。
- 按页面与客户端可能存活的时间保留旧资源,之后依据策略清理。
保留期限应结合 HTML 缓存、长时间打开的标签页、Service Worker、回滚窗口和资源成本制定,没有适合所有站点的固定天数。现代前端可能在用户点击新页面时才加载分块脚本,旧标签页仍可能请求旧 chunk。
使用 release 目录和原子切换可以减少文件复制过程中的半成品状态,但如果旧资源只存在于已被移走的旧目录,入口切换后仍会失效。要确认资源 URL 能继续访问,而不是只确认磁盘上还留着备份目录。
多台源站、对象存储与 CDN 的部署还需检查同步是否完成;部分节点缺资源会表现为间歇故障。回退也必须恢复匹配的页面和资源集合,不能只替换 index.html。若发布涉及后端接口或数据库变更,还要单独核验前后兼容性。
WordPress 与 Service Worker 有额外的一层
WordPress 优化插件可能生成合并、压缩或延迟加载文件。更新主题、删除旧缓存目录与刷新页面缓存的顺序不当,会让已缓存 HTML 引用不存在的生成文件。
应先确认插件生成任务成功、目录可写、必要资源可访问,再按插件支持流程刷新相关页面缓存。不要直接删除整个 uploads 或主题目录,也不要在生产环境同时关闭所有插件试错。需停用优化功能时,应限定范围、备份设置并在维护窗口验证。
如果站点注册了 Service Worker,它还可能自行维护 Cache Storage 和请求拦截逻辑。浏览器强制刷新并不等于修复所有客户端。开发者工具里取消注册可以用于隔离测试,但会改变当前测试环境,不能替代面向用户的版本迁移与缓存更新设计。
当所有资源都正确返回,但 Console 显示 CSP 或 SRI 失败,应分别核对策略、nonce、哈希和实际内容。不要以关闭 CSP、移除全部完整性检查或改用不受信任镜像来恢复样式。
验收要包含旧客户端和回滚路径
修复后分别测试新会话、保留旧页面的会话、登录与未登录入口,并按影响范围验证移动端及主要资源分发路径。确认 CSS、入口脚本、按需分块、字体和关键图片均正常,页面交互也符合预期。
持续观察静态资源 404、MIME 拒绝、脚本异常与源站负载。单次首页返回 200 不代表整个发布正确;旧客户端请求旧资源的数量也有助于确定清理时机。
记录本次变更的页面版本、资源清单、缓存操作和回退步骤。若异常扩大,按原计划切回匹配的一整套产物,避免边修边覆盖而失去可追踪版本。能够说明是哪份页面引用了哪份文件,以及它为什么不可用,后续发布流程才有明确的改进点。
参考资料
资料核验日期:2026 年 10 月 27 日。本文命令与配置为说明性示例,未声称已在读者生产环境实测。




