Apache2 Proxy跨子域请求时Cookie请求头丢失问题排查
问题复现场景
api.example.com虚拟主机配置/internal路径反向代理到本地8760端口的Node.js服务,代理配置如下:
ProxyRequests on ProxyPreserveHost on ProxyPass /internal http://localhost:8760 ProxyPassReverse /internal http://localhost:8760
- 同源(源为
api.example.com)发起如下AJAX请求时,Node.js后端可正常读取Cookie头:
$.ajax({ type: "GET", url: "https://api.example.com/internal/ajax", dataType: "json", cache: false });
- 仅修改请求发起源为同根域下的
sample.example.com,其余请求参数不变时,跨域请求到达后端后仅Cookie头缺失,其余请求头正常。
核心原因
跨源请求默认会被浏览器剥离Cookie、Authorization等敏感身份凭证头,这是浏览器内置的安全限制,必须同时满足三个条件才会在跨域请求中携带Cookie:
- 前端请求显式开启携带凭证配置
- 服务端返回的跨域响应头明确允许凭证传输,且不能用通配符
*设置允许源 - 目标Cookie的作用域配置允许跨子域访问
分步修复方案
1. 前端请求开启跨域凭证配置
修改AJAX请求参数,添加跨域携带凭证的开关:
$.ajax({ type: "GET", url: "https://api.example.com/internal/ajax", dataType: "json", cache: false, // 新增以下两行配置 xhrFields: { withCredentials: true }, crossDomain: true });
其他请求客户端对应配置:原生fetch设置
credentials: 'include';axios设置withCredentials: true。
2. Apache补充跨域响应头配置
在api.example.com的虚拟主机配置中,为/internal路径添加跨域头:
注意:禁止将Access-Control-Allow-Origin设置为通配符*,否则跨域凭证配置不生效,必须明确声明允许的源
<Location /internal> # 单允许源直接写死即可,多子域场景可通过mod_rewrite校验请求Origin是否属于*.example.com后动态赋值 Header set Access-Control-Allow-Origin "https://sample.example.com" # 显式允许跨域携带凭证 Header set Access-Control-Allow-Credentials "true" # 声明允许的请求头 Header set Access-Control-Allow-Headers "Content-Type,Cookie,Authorization" # 声明允许的请求方法 Header set Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS" # 直接响应OPTIONS预检请求,无需转发到后端Node服务 RewriteEngine On RewriteCond %{REQUEST_METHOD} OPTIONS RewriteRule ^(.*)$ $1 [R=204,L] </Location> # 原有代理配置保留不变 ProxyRequests on ProxyPreserveHost on ProxyPass /internal http://localhost:8760 ProxyPassReverse /internal http://localhost:8760
配置完成后执行apachectl configtest校验配置无错,重启Apache服务生效。
3. 校验Cookie作用域配置
确保api.example.com下写入的Cookie满足跨子域访问要求:
- Cookie的
Domain属性设置为.example.com(前缀带点,覆盖所有example.com下的子域),如果Domain默认设置为api.example.com,跨子域请求无权携带该Cookie - HTTPS环境下Cookie需要开启
Secure属性,同时将SameSite属性设置为None,否则跨域场景下浏览器会拦截Cookie
Node.js(Express框架)写Cookie参考配置:
res.cookie('user_token', 'xxxx', { domain: '.example.com', httpOnly: true, secure: true, sameSite: 'None', maxAge: 7 * 24 * 3600 * 1000 });
所有配置修改完成后,清空浏览器站点缓存、旧Cookie后重新测试即可正常读取到跨域请求携带的Cookie头。
内容的提问来源于stack exchange,提问作者OneRice
相关产品推荐
相关产品推荐

