http/2 不改变跨域逻辑,但其头部压缩和多路复用会使响应头丢失更隐蔽;根本原因是配置冲突或作用域错位,需在重定向、rewrite及http/2上下文中显式补全带always的cors头并调大header缓冲。

HTTP/2 本身不改变跨域逻辑,但它的头部压缩和单连接多路复用特性会让某些响应头丢失问题更隐蔽——尤其是当 Nginx 在启用 HTTP/2 的同时又做重写、重定向或代理时,响应头丢失往往不是协议导致的,而是配置冲突或作用域错位引发的。关键不在“HTTP/2 怎么处理”,而在于你是否在 HTTP/2 上下文中正确延续了跨域所需的头透传与控制逻辑。
确保 HTTP/2 启用不影响 CORS 头输出
HTTP/2 不会自动过滤或丢弃 Access-Control-* 类响应头,但以下两点极易出问题:
- Nginx 的
add_header指令默认只对 2xx 响应生效;若后端返回 302 或 401,CORS 头就不出现在响应中——HTTP/2 下这个缺陷更明显,因为浏览器可能复用连接并缓存无 CORS 头的响应 - 使用
http2_max_field_size或http2_max_header_size过小,会截断长响应头(如带多个白名单域名的Access-Control-Allow-Origin),导致 CORS 头被截断或整个 header block 解析失败
重写(rewrite)或重定向(return / error_page)时手动补全 CORS 头
HTTP/2 下 rewrite 或 location 跳转不会自动继承父块的 add_header。只要用了 rewrite ... break、return 302 或 error_page 302 = @xxx,就必须在目标 location 或命名块中显式重新声明 CORS 头:
- 错误写法:只在主 location 加
add_header Access-Control-Allow-Origin "$http_origin" always;,但跳转进@handle_302后没重复加 - 正确做法:在
@handle_302块内也写add_header 'Access-Control-Allow-Origin' '$http_origin' always;和add_header 'Access-Control-Allow-Credentials' 'true' always; - 特别注意:
always参数不可省略,否则 302 响应不会携带这些头
避免 HTTP/2 与 proxy_buffering 冲突导致头截断
启用 HTTP/2 时若同时开启 proxy_buffering on(默认值),Nginx 可能提前发送响应头、延迟发 body,而部分客户端在 HTTP/2 流中会因 header block 不完整拒绝解析。若你观察到 OPTIONS 预检通过但后续请求拿不到自定义响应头,可尝试:
- 临时关闭缓冲:
proxy_buffering off;(仅用于排查) - 或确保
proxy_buffer_size足够大(如128k),尤其当响应头含大量Access-Control-Expose-Headers字段时 - 检查是否误配
proxy_hide_header—— 它在 HTTP/2 下依然生效,且会静默屏蔽指定头,连日志都难追踪
验证 HTTP/2 下实际发出的响应头
别依赖浏览器开发者工具的 “Response Headers” 标签页——它可能显示解压后的逻辑头,掩盖真实传输问题。推荐用命令行直接观测:
curl -v --http2 -H "Origin: https://example.com" https://your-domain.com/api/test- 看输出中
是否存在,以及是否出现在 302 或 401 响应中 - 对比禁用 HTTP/2 的请求(加
--http1.1)结果,确认差异是否由协议层引起











