开启gzip后nginx可能压缩options预检响应(如204),导致cors头被篡改或缺失;应通过gzip off、设置gzip_min_length≥1000或禁用gzip_static等方式彻底规避压缩,确保响应头纯净。

开启 gzip 后,Nginx 对 OPTIONS 预检响应(尤其是 204 状态)可能意外触发压缩逻辑,导致响应头被篡改、缺失,甚至返回非预期的 Content-Encoding 或 Content-Length,最终让浏览器判定预检失败。根本原因在于:gzip 默认对满足条件的响应启用压缩,而 OPTIONS 响应本应无体、极简,一旦被 gzip 干预,就容易破坏 CORS 头的完整性与语义合规性。
关闭 OPTIONS 响应的 gzip 压缩
最直接有效的方式是彻底排除 OPTIONS 请求进入 gzip 流程:
- 在处理 OPTIONS 的 location 或 server 块中,显式关闭 gzip:gzip off;
- 或更精准地用 gzip_disable "MSIE [1-6]\."; 配合正则,但不如直接关更可靠
- 若全局启用了 gzip,可在 if 块内关闭(需 Nginx ≥ 1.7.0):
if ($request_method = 'OPTIONS') {
gzip off;
return 204;
}
设置 gzip_min_length 过滤微小响应
即使 gzip 开启,只要响应体长度低于阈值,就不会压缩。OPTIONS 响应体为空(Content-Length: 0),但部分旧版 Nginx 在判断时存在边界行为:
- 强制设 gzip_min_length 1000;(即 1KB),确保所有空响应、极短响应(如 204、健康检查)全部跳过压缩
- 避免设为 0 或过小(如 1),否则可能因内部判断逻辑误触发压缩准备流程,干扰 header 输出
禁用 gzip_static 对 OPTIONS 的干扰
gzip_static on 会尝试查找 .gz 文件并直接返回,但它只作用于静态文件请求(如 GET /app.js)。虽然 OPTIONS 本身不会命中静态文件,但若 location 配置宽泛(如 location / { ... }),且内部有 rewrite 或 try_files,可能意外引入歧义路径。稳妥做法是:
- 不在处理 API 或跨域的 location 中启用 gzip_static
- 或将 gzip_static 严格限定在 location ~ \.(js|css|json)$ 这类明确静态资源路径下
验证响应头是否被 gzip 污染
关键看三点是否干净:
- 响应状态码必须是 204 No Content(不能是 200)
- 响应头中 Content-Length: 0 必须存在,且不能出现 Content-Encoding: gzip
- 所有 Access-Control-* 头必须完整、未被覆盖或截断(可用 curl -I -X OPTIONS 直接验证)
不复杂但容易忽略:gzip 和 OPTIONS 本就不该共存。只要确保预检响应绕过所有压缩环节,就能守住 CORS 头的纯净性与浏览器兼容底线。











