缓存之谜:为何你的应用总是无法自动更新?
你是否也经历过这样的场景:线上刚修复完bug并已经发布,得到的反馈还是存在问题。所发布的应用是内嵌在小程序中,经常会出现发布后没有更新到最新的版本。只能无奈地回复:"清一下手机缓存"。心里想如何能在发布完成后,立即让用户得到最新的版本。
如果这个场景让你感同身受,那么这篇文章就是为你准备的。提供一个一劳永逸的 Nginx 配置方案,让你的应用实时更新。
1. 缓存策略
我们必须理解浏览器缓存策略的优先级。服务器(如 Nginx)在 HTTP 响应中返回的 Cache-Control、Expires 等头部信息,才是浏览器必须严格遵守的"最高指令"。
因为我们使用Webpack等构建工具,在打包时为 JS、CSS 等静态资源生成独一无二的 Hash 值文件名。当文件变化,index.html文件中的引入文件也会变化,如果此时浏览器缓存了,请求的是旧的html,就会出现一直请求旧的页面。
js
main.1258d91412371.js
vendor.ant-design.59d332b0.js
理论上,只要文件内容发生变化,Hash就会改变,浏览器就要请求新的文件。
2. 解决方案
那么我们只需要保证每次请求的html是最新的就可以解决缓存问题。
我们只需要将nginx中的index.html强制不缓存:
js
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
前后整体流程是:
- 当浏览器请求
https://xxx.com/时,命中了location /规则。 - Nginx 返回了旧的的
index.html文件,但没有附加任何Cache-Control或Expires响应头。 - 浏览器或上游CDN看到这个"沉默"的响应,便启用自己的默认缓存策略,将
index.html缓存了一段时间。 - 当你部署新版本后,JS 文件名(例如
main.new-hash.js)虽然变了,但用户再次访问时,浏览器直接从缓存中取出了旧的index.html。 - 旧的 HTML 文件依然引用着旧的 JS 文件 (
main.old-hash.js)。 - 最终,用户看到的还是旧版本,那个让你抓狂的 Bug 依然存在。
- 如果此时新的nginx配置完成,每次请求命中
/index.html设置 - 获取了新的html,也就会获取新的js文件,那么问题就解决了。
3, CDN设置
如果你的应用部署在CDN上,确保CDN的缓存策略与你的 Nginx 配置保持一致。通常需要在CDN控制台设置缓存配置,使其"遵守源站(Origin)的 Cache-Control 头"。
| 文件类型 | 建议 TTL | 是否遵守源站 |
|---|---|---|
*.html |
0 秒 | 是 |
4. 注意点
当新的nginx配置后,不一定会立刻生效。还是要将手机缓存清理下,才能每次获取最新的页面。
5. 总结
最后总结一下:缓存的根本在于 HTTP 响应头是控制缓存的唯一权威 。通过在 Nginx 层实施精细化的缓存策略------让入口 HTML 永不缓存,让带 Hash 的静态资源永久缓存,才能做到实时更新。