企业网站完成页面开发以后,性能检查经常会遇到一个现象:页面已经压缩,图片体积也不算大,但重复访问时浏览器仍然不断请求相同的 CSS、JavaScript、字体和图片。
这种情况除了资源本身体积,还要检查服务器有没有向浏览器返回合理的缓存策略。
网站建设中的静态资源缓存并不是简单地把缓存时间设置得越长越好。HTML、带版本号的前端资源和经常替换的图片,更新方式不同,缓存策略也应该有所区别。
一、示例环境
下面使用一个便于复现的测试环境:
Linux 服务器
Nginx 1.24.x
普通静态企业网站
Chrome 或 Edge 开发者工具
CSS、JavaScript、PNG、WebP、SVG、WOFF2 等静态文件
不同 Nginx 版本的配置语法大体一致,实际部署前仍需要结合当前服务器配置检查。
先执行:
nginx -t
确认现有配置没有语法错误。
修改配置以后,也应该再次执行该命令,再重新加载 Nginx:
nginx -s reload
二、为什么不能所有文件都设置相同缓存时间
网站中的资源大致可以分成两类。
一类是 HTML 页面。
HTML 经常承担页面内容更新和资源版本切换入口。如果 HTML 被长期缓存,新版本已经部署,但浏览器仍然读取旧 HTML,就可能继续引用旧的 CSS 或 JavaScript。
另一类是带版本标识的静态文件,例如:
app.a81c2f.js
main.72bd91.css
logo.38f2a1.webp
文件内容变化以后,构建工具会生成新的文件名。旧文件即使被浏览器长期缓存,也不会影响新版本加载。
因此,这类资源更适合较长缓存。
三、给普通静态文件设置基础缓存
如果项目暂时没有使用文件指纹,可以先建立一套相对保守的缓存配置。
Nginx 示例:
location ~* .(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ {
expires 7d;
add_header Cache-Control "public, max-age=604800";
}
这里的含义是让符合扩展名的静态资源获得 7 天缓存时间。
expires 7d 会设置过期时间。
Cache-Control 则告诉浏览器资源可以缓存,以及缓存有效时间。
这类配置适合更新频率不高、文件名称又没有做版本化处理的网站。
如果企业网站后台经常直接覆盖同名图片,就不建议一开始把缓存时间设置得很长,否则上传了新图以后,部分访问者仍可能看到本地缓存的旧版本。
四、带文件指纹的资源可以单独处理
如果前端构建已经使用内容哈希,例如:
/assets/app.a81c2f.js
/assets/main.72bd91.css
那么 /assets/ 下的资源可以考虑较长缓存。
示例:
location /assets/ {
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable";
}
immutable 表示资源在有效期内不会发生变化。
这个配置有一个前提:文件内容发生变化时,文件名也必须变化。
如果仍然使用固定的:
app.js
style.css
却长期缓存,就容易出现新版本已经发布、浏览器还读取旧文件的问题。
所以缓存策略必须和前端发布方式配合,而不能单独看 Nginx 配置。
五、HTML页面尽量与静态资源分开
对于 HTML,可以使用更谨慎的策略。
例如:
location ~* .html$ {
add_header Cache-Control "no-cache";
}
no-cache 并不等于完全不允许浏览器保存,而是要求在使用缓存副本前进行重新验证。
服务器确认文件没有变化时,可以返回:
304 Not Modified
浏览器此时不需要重新下载完整内容。
这样既可以减少不必要的数据传输,又能降低新版 HTML 长时间无法更新的情况。
实际项目如果使用动态框架、反向代理或 CDN,还要结合上游缓存策略一起检查,不能只修改这一层配置。
六、修改配置后怎么判断有没有生效
配置完成后,不要只根据“页面感觉快了一点”判断。
可以打开浏览器开发者工具,进入:
Network
重新加载页面。
选择一个 CSS、JavaScript 或图片请求,在 Response Headers 中检查:
Cache-Control
Expires
ETag
Last-Modified
例如看到:
Cache-Control: public, max-age=604800
说明服务器已经返回对应缓存头。
然后再次刷新页面。
部分资源的 Size 或状态位置可能显示:
from memory cache
或者:
from disk cache
也可能出现:
304
这些现象说明浏览器开始按照缓存策略处理资源。
七、使用本机请求进一步检查
如果服务器上可以访问测试站点,也可以使用命令查看响应头。
例如测试本机静态资源:
curl -I http://127.0.0.1/assets/app.css
重点观察是否返回预期的:
Cache-Control
Expires
ETag
Last-Modified
如果 Nginx 配置里已经设置,但响应头没有出现,需要继续检查:
当前请求是否进入了正确的 location
是否有上层反向代理覆盖响应头
是否存在 CDN 缓存规则
是否有其他 add_header 配置影响继承
实际请求的资源路径是否与规则匹配
八、更新后仍看到旧文件怎么排查
如果静态缓存已经启用,后续部署新版本时又出现旧样式,可以依次检查几个位置。
先看文件名称有没有发生变化。
如果文件内容更新但名称没有变化,浏览器可能继续使用原缓存。
再看 HTML 是否已经引用新资源。
有时服务器里新 CSS 已经存在,但 HTML 仍然指向旧文件。
还要检查 CDN 或其他缓存层。
浏览器缓存、代理缓存、CDN 缓存和服务器缓存不是同一层,不能只清理浏览器以后就判断问题已经解决。
九、不要把“关闭缓存”当成长期处理方式
开发阶段为了方便调试,经常会在开发者工具中勾选:
Disable cache
这样有利于观察资源变化。
但正式网站不能依靠让访问者关闭缓存解决版本更新问题。
更稳定的方式,是从资源命名、缓存时间和页面更新关系入手。
经常变化的入口文件采用较谨慎策略,内容改变就生成新文件名的静态资源则可以使用较长缓存。
十、验证结果应该看什么
完成配置后,可以检查以下结果:
静态资源响应中存在对应的缓存头;
再次访问时不需要反复传输所有静态文件;
更新带哈希值的前端资源后,新页面能够正常引用新文件;
HTML 更新后不会因为长时间缓存而一直停留在旧版本;
浏览器控制台没有因为缓存配置产生资源缺失或版本不匹配。
网站建设中的缓存配置真正要解决的是“哪些文件可以复用,哪些文件需要及时确认更新”。
把 HTML 和版本化资源分开处理,再通过响应头和浏览器 Network 面板验证,比简单给整个网站设置一个统一缓存时间更容易维护。
本文由梓彤超越(武汉)科技有限公司整理。