核心是gzip_static优先服务预压缩.gz文件(零cpu开销),gzip on全局兜底;构建阶段必须产出同名.gz文件并同步时间戳,nginx需在静态资源location块中精准配置gzip_static on。

要让 Nginx 对静态内容实现“智能压缩”,核心不是靠实时判断,而是分清两种路径:用 gzip_static 优先服务已预压缩的 .gz 文件(零 CPU 开销),再用 gzip on 兜底处理漏掉的或动态生成的内容。真正高效、可落地的配置,是两者协同而非二选一。
构建阶段:提前生成 .gz 文件
静态资源(JS、CSS、HTML、SVG 等)必须在打包时就产出同名 .gz 文件,不能等请求来了再压。否则 gzip_static 就无文件可读。
- Webpack 项目:用 compression-webpack-plugin,设
algorithm: 'gzip'和deleteOriginalAssets: false(原始文件必须保留) - Vite 项目:用 vite-plugin-compression,配置
ext: '.gz',filter匹配常见文本类型,避免压缩 HTML(部分环境会触发 403) - 已有部署补救:批量生成,例如
find /usr/share/nginx/html -type f \( -name "*.js" -o -name "*.css" -o -name "*.svg" \) -exec gzip -c9 {} \; -exec mv {}.gz {}\.gz \;
完成后建议同步时间戳:touch -r index.js index.js.gz,避免缓存不一致
Nginx 配置:精准启用 gzip_static
gzip_static 不是锦上添花的选项,而是静态资源响应的主通道。它必须放在具体服务静态文件的 location 块内,且位置关键。
- 只写
gzip_static on;—— 不要和gzip on写在同一 location;不要重复配gzip_types(它对类型无感,有 .gz 就试) - 典型 React/Vue 部署示例:
location / {<br> root /usr/share/nginx/html;<br> try_files $uri $uri/ /index.html;<br> gzip_static on;<br>}
注意:gzip_static在try_files之前生效,若重写路径导致 .gz 文件找不到,需检查目录结构是否匹配 - 不要在
http或server块顶层写gzip_static on,它只在能定位到真实文件的 location 中有效
兜底与协同:gzip on 全局开启但职责分明
gzip_static 负责已预压缩的静态文件;gzip on 则负责 API 响应、未打 .gz 的旧资源、或后端透传内容——二者共存,但分工清晰。
- 在
http块中全局开启:gzip on;<br>gzip_min_length 1000;<br>gzip_comp_level 6;<br>gzip_types text/html text/css application/javascript application/json text/xml application/xml;
- 务必包含
text/html—— 否则 HTML 响应不会被兜底压缩 - 禁用
gzip_vary on:虽然文档常推荐它,但在使用 .gz 文件时开启会导致 CDN 缓存分裂;实际生产中更推荐关掉,由构建时加 ETag 或 Cache-Control 控制缓存粒度
验证是否真正生效
别只信浏览器 Network 面板——它可能显示的是 CDN 返回的头。要确认是 Nginx 在起作用,得绕过 CDN 直连:
- 用 curl 测试:
curl -H "Accept-Encoding: gzip" -I http://localhost/style.css
看响应头是否有Content-Encoding: gzip,且Content-Length明显小于原始文件 - 对比两个请求:
curl -s -H "Accept-Encoding: gzip" http://localhost/app.js | wc -ccurl -s -H "Accept-Encoding:" http://localhost/app.js | wc -c
差值应接近本地 .js.gz 文件大小 - 检查 Nginx 错误日志:若 .gz 文件存在但没返回,常见原因是权限不足、时间戳不同步、或 location 路径没匹配到真实文件路径











