React中POST请求为什么被CORS拦截?预检请求没发出去?

慕容雨萱 阅读 59

在React项目里用fetch发POST请求到第三方API时,浏览器突然报CORS错误。我明明设置了headers里的Content-Type为application/json,但控制台显示”Response to preflight request doesn’t pass access control check”。

试过在headers加mode: ‘cors’和credentials: ‘omit’,但问题依旧。奇怪的是同样的代码在本地测试环境没问题,部署到生产环境就拦截了。难道预检请求没发出去?代码如下:


const sendRequest = async () => {
  try {
    const response = await fetch('https://api.example.com/data', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + token
      },
      body: JSON.stringify({ name: 'test' })
    });
    return response.json();
  } catch (error) {
    console.error('CORS error:', error);
  }
};

检查Network面板发现只有POST请求被拦截,没有看到OPTIONS预检请求。生产服务器是Nginx配置的,是不是需要特别开启预检支持?

我来解答 赞 12 收藏
二维码
手机扫码查看
2 条解答
一丽珍
一丽珍 Lv1
你这个问题我太熟悉了,之前踩过同样的坑。核心问题其实是:浏览器发不出OPTIONS预检请求,是因为后端没正确响应这个请求,不是前端代码的问题。

你代码里写得没问题,但关键点在于:当请求满足「非简单请求」条件(比如POST+application/json+自定义header),浏览器会先发OPTIONS预检请求,如果这个OPTIONS请求本身没被服务器正确处理,或者返回了错误状态码/缺失CORS头,浏览器就直接拦截后续的POST请求,所以你在Network里看不到OPTIONS——它压根没发出去或者被浏览器悄悄吞了。

先确认两件事:

1. 后端(api.example.com)有没有处理OPTIONS请求?
比如Nginx里要加个location匹配OPTIONS,返回204或200,带上这些响应头:

location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Content-Type' 'text/plain; charset=utf-8';
return 204;
}
# 正常代理逻辑...
}


注意 Authorization 这个header必须显式加在 Access-Control-Allow-Headers 里,不然预检会失败——你请求里带了 Bearer token,属于自定义header,必须允许。

2. 检查生产环境的API是否真的支持OPTIONS请求。可以手动用curl测一下:

curl -i -X OPTIONS 
-H "Origin: https://your-domain.com"
-H "Access-Control-Request-Method: POST"
-H "Access-Control-Request-Headers: Content-Type, Authorization"
https://api.example.com/data


如果返回里没有 Access-Control-Allow-Origin 或者状态码是404/500,那就是后端没配好。

本地没问题可能是因为本地开发用的是webpack-dev-server这类代理,请求其实是打到localhost再转发的,天然绕过了CORS;但生产环境是直接跨域请求,CORS规则就严格生效了。

可以试试这样改Nginx配置(如果你能改后端配置的话):

add_header 'Access-Control-Allow-Origin' 'https://your-production-domain.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;

然后处理完OPTIONS后一定要 return 204;,别让请求继续往下走。

如果后端是别人管的,比如第三方API,那可能真不支持自定义header……这种情况只能让后端加白名单,或者你前端改用代理(比如自己搭个Node中间层转发请求)。

顺便吐槽一句:CORS问题90%都是后端没处理OPTIONS,不是前端的锅,别在 mode: 'cors' 上浪费时间了,它默认就是cors模式。
点赞 2
2026-02-27 08:07
爱学习的颖杰
这个问题其实是CORS预检请求的典型问题,先分析一下原因。你提到生产环境有问题,但本地没问题,这基本可以确定是服务器端的CORS配置差异导致的。浏览器在发POST请求之前会先发一个OPTIONS请求来确认服务器是否允许跨域访问,这个叫预检请求。如果预检请求没通过,浏览器直接拦截后续的POST请求。

从你的描述来看,生产环境用的是Nginx,很可能是Nginx没有正确处理OPTIONS请求,或者响应头里缺少必要的CORS字段。你可以按照以下步骤排查和解决:

先检查一下Nginx的配置文件,确保它能正确处理OPTIONS请求。可以在server块里加上类似下面的配置:


if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET, POST, OPTIONS;
add_header Access-Control-Allow-Headers Authorization, Content-Type;
return 204;
}


这段配置的意思是,当收到OPTIONS请求时,直接返回204状态码,并添加必要的CORS响应头。

然后,再检查一下Nginx对其他请求的CORS支持,确保每个正常的请求也带上这些响应头。比如:


add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET, POST, OPTIONS;
add_header Access-Control-Allow-Headers Authorization, Content-Type;


另外,如果你的服务端用了反向代理,确保代理层不会把OPTIONS请求过滤掉或者改写。有时候代理层会默认丢弃非GET/POST请求,这就导致预检请求根本到不了后端。

最后,补充一点,你在fetch里加的mode: 'cors'其实是多余的,因为fetch默认就是cors模式。而credentials: 'omit'可能会导致某些需要认证的接口出问题,建议去掉试试。

改完Nginx配置后记得重启服务:sudo nginx -s reload,然后清空浏览器缓存再试一次。如果还是有问题,可以用curl命令手动模拟一个OPTIONS请求,看看返回的响应头是不是符合预期。比如这样:


curl -X OPTIONS -H "Origin: http://your-react-app.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: Authorization, Content-Type" https://api.example.com/data -I


总之,重点是让Nginx正确处理OPTIONS请求并返回合适的CORS头。搞定这个,问题应该就解决了。
点赞 7
2026-02-19 15:00