静态资源“热重载”实为构建时文件哈希+html引用更新+nginx强缓存配合实现;nginx对js/css等设1年缓存并加immutable,html禁用缓存,确保url变更即生效。

静态资源缓存本身不支持“热重载”,因为缓存是浏览器或代理层对已响应内容的复用机制;Nginx 作为服务端,无法主动通知客户端“这个缓存已失效”。所谓“自动热重载”实际是通过合理配置缓存策略 + 构建时版本控制(如文件哈希)来实现资源更新后立即生效,避免手动清缓存或用户强刷。
核心思路:用内容指纹替代时间戳式刷新
不依赖 Cache-Control: max-age 的长时效硬缓存(否则改了 JS 用户看不到),也不靠 ETag/Last-Modified 被动比对(效率低、仍可能命中旧缓存)。而是让每个资源文件名携带唯一哈希,例如:
-
app.js→app.a1b2c3d4.js -
style.css→style.e5f6g7h8.css
构建工具(Webpack/Vite/Rollup)自动生成带哈希的文件,并在 HTML 中引用新文件名。Nginx 只需按扩展名设置强缓存,浏览器发现 URL 变了,自然请求新资源——这才是真正“自动更新”的关键。
Nginx 缓存配置示例(推荐)
在 server 或 location 块中添加:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
说明:
-
expires 1y:告诉浏览器缓存一年,极大减少重复请求 -
Cache-Control: public, immutable:表示资源可被 CDN 和浏览器共享,且承诺内容永不变更(配合哈希文件名才安全) - 不启用
ETag(默认关闭)或Last-Modified:避免协商缓存干扰,提升命中率
HTML 文件必须禁用缓存
HTML 是入口,必须每次检查更新,否则用户永远加载不到新资源链接:
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
也可用更简洁写法:
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache";
}
开发阶段可加一层简易热更新辅助(非生产必需)
若想在本地开发时看到“保存即刷新”,这不是 Nginx 的职责,而应由前端工具链完成:
- Vite/Webpack Dev Server 自带 HMR(模块热替换),无需 Nginx 参与
- 若用 Nginx 代理开发服务器(如反向代理到
localhost:3000),确保 proxy_pass 不缓存响应:proxy_cache_bypass $http_upgrade;proxy_no_cache $http_upgrade;
生产环境不需要这套逻辑,它只增加复杂度且无实质帮助。
不复杂但容易忽略:缓存是否生效,最终取决于 URL 是否变化 + HTML 是否及时拉取新 URL。Nginx 的角色是高效交付带哈希的静态文件,并坚定地告诉浏览器“这个文件一年内不会变”。其余交给构建工具和浏览器即可。











