jQuery AJAX跨域请求未向Spring Cloud Gateway传递Cookie问题
问题根因
这种请求到了网关之后空无所有的情况,是几处典型的配置错位叠加导致的,和你写的全局过滤器逻辑没关系:
1. CORS配置完全放错了位置
你在8080端口的JSP服务端,给设置Token Cookie的响应加了两个CORS头:
response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");
这部分配置对当前场景毫无作用:
- 浏览器的跨域校验逻辑是:哪个服务端接收到了跨域请求,就校验哪个服务端返回的CORS响应头。现在你从8080的页面发请求到8081的网关,做跨域校验的主体是8081的网关,你在8080的响应里写的CORS规则,浏览器在校验网关响应的时候根本不会读取。
- 你把8080的允许跨域源设为
http://localhost:8081,相当于给8080的接口设置了“只允许来自8081的页面跨域访问”的规则,和你从8080发请求到8081的需求完全相反。
最关键的影响是:你的AJAX请求带了自定义的Authorization头,属于需要浏览器先发OPTIONS预检请求的场景。因为8081的网关根本没有配置对应的CORS规则,浏览器拿到预检响应的非合规模态后,直接拦截了后续的实际请求——也就是说,你的请求压根就没进到网关的过滤器逻辑里,自然看不到任何Cookie和请求头。
2. 前端代码里设置了非法的请求头
你在AJAX的beforeSend钩子里写了:
xhr.setRequestHeader('Access-Control-Allow-Credentials', 'true');
这是典型的API误用:Access-Control-Allow-Credentials是浏览器规范定义的服务端响应头,前端XHR根本不允许设置这个头,写了也会被浏览器直接过滤,还会因为触发了非安全请求头规则,直接导致预检请求失败。
3. Cookie的默认安全策略阻止了跨源携带
你现在设置Cookie时,没有手动指定SameSite属性。按照Chrome 80+、Firefox 75+的默认安全规则,没有显式指定SameSite的Cookie会被自动标记为SameSite=Lax,这种属性的Cookie只会在顶层跳转的GET请求中被携带,跨源的XHR、POST请求哪怕是同域名不同端口的跨源场景,浏览器也不会主动把Cookie附带到请求里。
再加上你把Secure属性的配置注释掉了,进一步让浏览器拒绝在非安全的跨源场景下携带这个Cookie。
4. 逻辑上的冗余
你现在的前端代码本来就是通过readCookie('access_token')手动读Cookie值,再塞到Authorization请求头里发给网关的——这种场景下根本不需要依赖浏览器自动携带Cookie的逻辑。只要CORS校验通过,手动读取的Token值会正常通过请求头发送到网关,不需要让浏览器自动附带Cookie。
修复方案
- 删掉8080端JSP代码里那两行完全无效的CORS响应头,CORS规则的配置主体应该是接收到跨域请求的8081网关,而不是发请求的8080端
- 在Spring Cloud Gateway侧配置全局CORS规则:
- 允许源精确匹配
http://localhost:8080,绝对不能用* - 开启跨域凭据支持:
Access-Control-Allow-Credentials: true - 允许的请求头列表加入
Authorization、Content-Type - 对所有OPTIONS预检请求直接返回200,不要走后续的路由匹配和过滤器链
- 允许源精确匹配
- 删掉AJAX代码
beforeSend里设置Access-Control-Allow-Credentials的无效代码 - 如果你确实需要浏览器自动携带Cookie,需要在设置Cookie时手动指定兼容的属性:
SameSite=None+Secure(本地http环境下,Chrome对localhost有特殊兼容策略,允许这两个属性生效,生产环境必须基于HTTPS部署) - 建议把之前注释掉的
HttpOnly配置打开,避免前端脚本被XSS攻击窃取Token
内容的提问来源于stack exchange,提问作者Niranga Sandaruwan

