要让nginx同时发挥gzip压缩和expires长效缓存作用,关键在于gzip必须在缓存写入前完成、启用gzip_vary on使缓存区分编码版本、精准设置gzip_types避免重复压缩,并通过资源指纹(如contenthash)配合expires max与immutable实现真正长效加速。

要让 Nginx 同时发挥 gzip 压缩和 expires 长效缓存的作用,关键不是“先压后缓”或“先缓后压”,而是让压缩结果被正确识别、分别缓存,并配合资源指纹实现真正可落地的长效加速。
gzip 必须在缓存写入前完成
默认情况下,Nginx 的 proxy_cache 或 fastcgi_cache 缓存的是原始响应体。如果后端返回未压缩内容,而 gzip 在缓存之后才执行,那每次请求都要重新压缩——既浪费 CPU,又没节省带宽。
- 必须开启 gzip on;,并设置 gzip_vary on;,这样 Nginx 才会在响应头中添加
Vary: Accept-Encoding -
Vary头是核心:它告诉缓存系统(包括浏览器和 Nginx 自身缓存)“同一 URL 可能有多个版本”,比如text/css有未压缩版和 gzip 版,应分开存储 - 压缩类型要精准,避免对已压缩资源(如 JPG、PNG、woff2)再 gzip:
gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;
expires 配置要匹配资源稳定性
长期缓存只适用于内容不变、URL 随内容变化的资源,比如构建后带哈希的 JS/CSS/字体/图标。
- 推荐用前缀匹配静态目录,性能优于正则:
location ^~ /static/ { expires max; add_header Cache-Control "public, immutable, max-age=315360000"; } - 绝对不要在根 location 或 HTML 路径上设 long cache:
location / { expires 1y; }会把 HTML 和 API 接口也缓存,导致页面无法更新 - 不带哈希的资源(如
logo.png)建议设expires 30d;,并配Cache-Control "public, max-age=2592000",避免用户卡在旧版
两者协同生效的关键验证点
配置完不能只看语法是否通过,必须确认压缩与缓存实际共存且被浏览器正确使用。
- 用
curl -I https://site.com/app.abc123.js检查响应头:
应同时存在Content-Encoding: gzip、Expires、Cache-Control,且Vary包含Accept-Encoding - 浏览器开发者工具 → Network → 刷新两次:
第二次状态码应为200 (from disk cache),且 Size 显示 “from disk cache” 或 “from memory cache” - 若看到
304 Not Modified,说明走了协商缓存,不是强缓存,需检查是否漏了immutable或文件名没更新
构建流程必须配套支持
再好的 Nginx 配置,没有前端构建配合,长效缓存就是双刃剑。
- Webpack/Vite/Rollup 等工具必须启用
[contenthash],生成类似main.a1b2c3.js的文件名 - HTML 中的 script/link 标签引用路径必须由构建自动更新,确保新 HTML 指向新哈希文件
- 这样即使缓存设为 10 年,只要文件名一变,浏览器就视为全新资源,自然绕过旧缓存,无需手动刷新 CDN 或清缓存











