核心是nginx sendfile开启时绕过mtime检测,导致浏览器协商缓存失效;临时关sendfile可验证,生产应改用哈希url+强缓存策略,并确认文件路径、权限及响应头一致性。

这个问题核心不在浏览器“不听话”,而在于 Nginx 和浏览器两层缓存机制叠加,再加上文件路径或权限没对上,导致你改了文件,它却坚持用旧的。
检查 Nginx 的 sendfile 是否干扰了更新
sendfile 开启时,Nginx 会绕过用户态直接从内核发文件,跳过了常规的文件修改时间(mtime)检测逻辑。浏览器如果依赖 Last-Modified 做协商缓存,就可能收不到“文件已变”的信号。
- 临时验证:在 nginx.conf 的 server 或 location 块里加一行 sendfile off;,然后
nginx -s reload - 若此时刷新能立即看到新内容,说明 sendfile 是诱因;生产环境不建议长期关闭,后续应配合版本化 URL 或强缓存策略来规避
确认静态文件是否真的被更新到服务器指定位置
前端构建后上传 dist,但 Nginx 的 root 指向的可能是旧目录,或者上传过程覆盖不全(比如只传了 JS,漏了 CSS)。
- 用
curl -I http://yourdomain.com/index.js查看响应头里的 Last-Modified 或 ETag,和服务器上对应文件的实际修改时间对比 - 执行
nginx -T | grep root确认当前生效的 root 路径,再进该目录用ls -l核对文件时间戳 - 注意:若用 rsync 上传,记得加
-a参数保留时间戳;若手动解压,时间戳可能被重置
排查浏览器缓存是否“固执己见”
即使服务端返回了新内容,浏览器也可能因强缓存(Cache-Control: immutable / max-age=31536000)拒绝重新请求。
- 打开浏览器开发者工具 → Network 标签 → 刷新页面 → 找到 JS/CSS 文件 → 查看 Headers 里的 Cache-Control 和 Expires
- 若看到
max-age=31536000或immutable,说明资源被设为“永不过期”,必须改 URL(如加哈希后缀)才能触发新请求 - 开发阶段可临时加配置禁用强缓存:
expires -1; add_header Cache-Control "no-cache";
别忽略文件系统权限和 SELinux(Linux)
文件确实更新了,但 Nginx Worker 进程没有读权限,它可能静默返回旧缓存副本,或干脆报 403 却被前端掩盖。
- 运行
ps -aux | grep nginx看 worker 进程以哪个用户运行(通常是 www-data 或 nginx) - 执行
ls -l /var/www/your-dist/,确认该用户对文件有 r 权限,对目录有 r-x 权限(x 对目录意味着可进入) - CentOS/RHEL 系统还需检查 SELinux:
getenforce若为 Enforcing,尝试临时setenforce 0测试是否恢复;长期方案是chcon -R -t httpd_sys_content_t /var/www/your-dist











