为什么浏览器发送的 OPTIONS 请求没有携带 Cookie?

法霞 阅读 35

我在做跨域请求时发现,预检请求(OPTIONS)好像没带 Cookie,但正式请求却有。这是为啥?

我用的是 fetch 发请求,设置了 credentials: 'include',但 OPTIONS 请求在 DevTools 里看请求头根本没有 Cookie 字段,导致后端校验失败。

我来解答 赞 11 收藏
二维码
手机扫码查看
2 条解答
丽红(打工版)
这其实是浏览器的行为,预检请求 OPTIONS 本来就不会带 Cookie。预检请求是浏览器自动发起的,它的作用就是询问服务器当前请求是否被允许,所以只包含最基本的 CORS 头信息。

你用 fetch 设置了 credentials: 'include' 是对的,但要注意后端也要配合。在处理实际请求时,服务端需要设置 Access-Control-Allow-Credentials: true 这个响应头。

另外别忘了配置正确的 Access-Control-Allow-Origin,它必须是具体的源地址,不能是通配符 * 。如果这些都设置了,正式请求就会带上 Cookie。

最后提醒下,如果你用的是 Nginx 做反向代理,记得检查 proxy_set_header 配置,有时候代理层会把 Cookie 给弄丢。

fetch('https://example.com/api', {
method: 'POST',
credentials: 'include',
// 其他配置
})


// PHP 示例
header("Access-Control-Allow-Origin: https://yourdomain.com");
header("Access-Control-Allow-Credentials: true");


这个机制设计上有点烦人,不过确实保护了安全性,虽然调试的时候挺让人头疼的。
点赞
2026-03-27 19:11
书生シ利利
这属于正常现象,不是你的代码问题。

OPTIONS 预检请求是浏览器自动发出的,目的是询问服务器"我能不能发正式请求"。按照 CORS 规范,预检请求不应该携带 Cookie、认证信息这些敏感数据,所以浏览器压根就不会把 Cookie 带上。

问题出在你后端拦截器上。后端不应该对 OPTIONS 请求做登录校验,应该直接放行。

以前踩过这个坑,后端拦截器代码大概长这样,你照着改:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// OPTIONS 请求直接放行,不校验
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setStatus(HttpServletResponse.SC_OK);
return true;
}

// 其他请求才做登录校验
String token = request.getHeader("Authorization");
// 校验逻辑...
return true;
}


关键点就两个:

第一,OPTIONS 请求必须放行,别让它走登录校验逻辑。

第二,响应头里 Access-Control-Allow-Credentials 要设为 trueAccess-Control-Allow-Origin 不能写 *,必须写具体的域名,否则带 Cookie 的正式请求也会失败。

前端你的 credentials: 'include' 设置没问题,不用改。
点赞 1
2026-02-28 15:03