解决本地前端向远程服务端发送跨域请求时,cookie无法携带问题
环境
- 前端:vue3 + vite
- 后端:SpringBoot 3.3.4
场景描述:在本地启动前端项目时,调用远程服务端接口登录成功后,发现session的登录态丢失
问题分析:前端[http://localhost:5173/]调用后端接口[http://154.8.193.216:7777/api],属于跨域请求,因此我在服务端加上了CORS跨域配置,其中设置了 config.setAllowCredentials(true),表示允许前端在发送跨域请求时携带凭证(cookie), 并且前端Axios配置中加上了withCredentials: true,请求时会带上cookie凭证,但实际上在浏览器Network面板上发现当login登录接口调用成功后,紧接着调用的queryAll接口的请求头中没有cookie这一项,说明了发送请求时浏览器并没有带上cookie,并且在响应头中的Set-Cookie这一项出现了警告

Set-Cookie————JSESSIONID=C57AFC4D279D8FFF8904348A2B214112; Max-Age=2592000; Expires=Tue, 19 Aug 2025 14:24:02 GMT; Path=/api; HttpOnly
此Set-Cookie标头未指定”SameSite”属性,它默认为”SameSite=Lax,”并被阻止,因为它来自跨站点响应,而不是对顶级导航的响应。必须为此Set-Cookie设置“SameSite=None”才能实现跨站点使用。
这个警告是说:浏览器在处理跨站点的 AJAX/Fetch 响应时,如果它看到 Set‑Cookie 里没有 SameSite=None,就会把这条 Cookie 当成 SameSite=Lax,直接拒绝存储或发送给跨站请求。
SameSite(Cookie属性)
-
作用域:它是一个 Cookie 的属性,用来告诉浏览器「在什么场景下,可以把这个 Cookie 附带到请求里发送」
-
取值:
-
Strict:跨站点(cross‐site)的任何请求都不发送,只有顶级导航才会。 -
Lax(默认):允许顶级导航的 GET 请求带 Cookie,但 AJAX/fetch/POST 等子资源请求不带。 -
None:放行所有请求(包括跨站点的 AJAX),但必须配合 Secure(HTTPS)才能生效。
-
从上面我们可以看到当前响应头中的Set-Cookie里没有SameSite属性,因此SameSite取默认值Lax,而Lax属性值表示在跨域请求下,无法携带cookie, 只有SameSite取值为None时,才能跨站点发送请求, 因此我首先想到的解决方案是在服务端中的cookie配置中加上same-site:none,这样响应头中的Set-Cookie就会被写入SameSite=None这一项
session:
cookie:
max-age: 2592000
same-site: none
重新部署测试后,发现响应头中确实加上了SameSite这一项,不过queryAll接口的请求头中仍然没有携带cookie,问题还是未能得到解决

Set-Cookie————JSESSIONID=D1C5452C6A1F9E43453ECF32F13C6E23; Max-Age=2592000; Expires=Tue, 19 Aug 2025 15:17:32 GMT; Path=/api; HttpOnly; SameSite=None
但是出现了新的警告:尝试通过Set-Cookie标头设置Cookie时被阻止,因为它具有”SameSite=None”属性,但没有使用"SameSite=None"所必需的"Secure"属性。
这个警告是浏览器在执行 Set‑Cookie 时的一道硬性校验:只要你给 Cookie 标记了 SameSite=None,就必须同时加上 Secure,否则浏览器会一概拒绝。
因此我在服务端的配置文件中又加上一项secure:true
session:
cookie:
max-age: 2592000
same-site: none
secure: true
重新部署测试后,响应头中确实加上了Secure,不过queryAll接口的请求头中仍然没有携带cookie,问题还是未能得到解决

Set-Cookie————JSESSIONID=A444FB229F2DD86BB7C6B8B8589E72CF; Max-Age=2592000; Expires=Tue, 19 Aug 2025 15:35:32 GMT; Path=/api; Secure; HttpOnly; SameSite=None
但又出现了新的警告:尝试通过Set-Cookie标头设置Cookie时被阻止,因为它具有”Secure”属性,但未通过安全连接发送。
这个警告说的是浏览器只允许在“安全上下文”(HTTPS 或者 localhost/127.0.0.1)下设置带 Secure 属性的 Cookie,任何通过 HTTP(非加密连接)下发的带 Secure 的 Set‑Cookie 都会被直接丢弃
我的后端接口地址使用的是http(非https),所以通过在后端配置ssl证书来启用https,可以解决请求无法携带cookie的问题(由于条件有限,这里不做演示)
通过以上实验,我们可以看出如果要在跨域请求中携带cookie,响应头中的Set-Cookie必须包含SameSite=None,而添加了SameSite=None就需要配合Secure,使用了Secure又必须保证请求是Https
本地前端调用远程服务端接口,需要后端配置ssl证书来启用Https,这种方法太麻烦了,有没有其他解决方案呢?
在这之前,首先我们需要知道一个非常重要的概念,就是浏览器对“同一站点”(same‐site)和“跨站点”(cross‐site)的请求会有两套不同的 Cookie 发送规则
same-site请求(注册域名相同,不论端口)—>默认就能带 Cookie
cross-site请求(注册域名不同)->会被浏览器默认的SameSite=Lax拦截,必须SameSite=None; Secure + HTTPS + 前端withCredentials: true + 后端CORSallowCredentials(true)才能携带cookie
我这里属于cross-site(跨站点)请求,因此上述采用的是跨站点请求的cookie携带规则,这也就是为什么本地前端调用本地后端,远程前端调用远程后端(同一主机)可以携带cookie的原因,因为它们都属于same-site(同站点)请求,因此下面的第二种解决方案我们通过“同源代理”来发送same-site(同站点)请求
“同源代理”就是利用本地开发服务器做一个反向代理,把发到[http://localhost:5173/api/...]的请求转发到真正的后端[http://154.8.193.216:7777/api...],这样就能保证请求的主机名始终是localhost,浏览器看见的URL都是http://localhost:5173,就认为它和页面同源,不触发跨域检查,具体代码实现如下
// myAxios.ts
const myAxios = axios.create({
baseURL: '/api',
withCredentials:true,
});
// vite.config.ts
server: {
proxy: {
// 将 /api 前缀的请求代理到后端,并映射到后端的 /api 路径
'/api': {
target: 'http://154.8.193.216:7777/api',
changeOrigin: true,
// 去掉本地请求的 /api 前缀后再发送给后端
rewrite: (path) => path.replace(/^\/api/, '')
},
},
}
此时在浏览器中可以看到当前请求的请求头中带上了cookie,问题得到解决

除了上面两种方案,还有一种解决方案是更换火狐浏览器,和Edge, Chrome浏览器不同,火狐浏览器Cookie不会受到SameSite=Lax的限制,可以在发送跨站点请求时正常携带cookie
或者不使用Cookie-Session的登录模式,改用Token + Authorization,登录成功后后端返回 JWT(写在响应体里),前端存到 localStorage 或内存, 后续接口通过 Authorization: Bearer
总结:本地前端向远程服务端发送请求时,要想携带cookie,可采用一下四种方案:
1. 给后端开HTTPS
2. 本地开发用“同源代理”
3. 使用火狐浏览器
4. 改用Token + Authorization

浙公网安备 33010602011771号