Axios/Fetch GET请求转为OPTIONS请求返回401跨域报错问题
问题背景
已掌握CORS预检请求相关机制,服务端已声明支持OPTIONS方法请求。
问题现象
- 使用Postman、reqbin等所有在线API测试工具调用目标接口均可正常返回
- 使用Axios或原生fetch发起GET请求时,浏览器自动触发OPTIONS预检请求,该请求返回401 Unauthorized状态码,请求被浏览器拦截
环境说明
- 本地开发环境基于localtunnel暴露服务,使用Next.js默认服务端配置
- 服务端已参照标准Nginx CORS配置指引完成规则配置,配置文件路径为
/example.com/conf/nginx/cors.conf
前端复现代码
var myHeaders = new Headers(); myHeaders.append("Access-Token", "token-here"); var requestOptions = { method: 'get', headers: myHeaders, crossDomain: true, redirect: 'follow' }; fetch("https://example.com/x/wp-json/api", requestOptions) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log('error', error));
浏览器控制台报错
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.com/xx/wp-json/x/api. (Reason: CORS preflight response did not succeed). Status code: 401.
(Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘http://localhost:3000, http://localhost:3000’)
服务端返回的CORS相关响应头
| 响应头 | 值 |
|---|---|
| access-control-allow-credentials | true |
| access-control-allow-headers | Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type |
| access-control-allow-methods | OPTIONS, GET, POST, PUT, PATCH, DELETE |
| access-control-allow-origin | https://localtunnel-URL.loca.lt |
| content-type | application/json; charset=UTF-8 |

问题根因
- OPTIONS预检请求被鉴权逻辑拦截:前端请求携带了自定义头
Access-Token,属于会触发CORS预检的场景,当前服务端虽然声明支持OPTIONS方法,但未对OPTIONS请求关闭鉴权校验,OPTIONS请求不会携带业务鉴权凭证,直接被鉴权逻辑拦截返回401,导致预检失败。 Access-Control-Allow-Origin配置错误:当前配置写死的允许源为localtunnel分配的域名,但浏览器实际发起请求的源为http://localhost:3000,同时配置存在重复拼接Origin的问题,返回的允许源值和请求实际源不匹配,被浏览器拦截。- 允许请求头配置缺失:当前
Access-Control-Allow-Headers列表未包含前端自定义传递的Access-Token头,即使预检请求返回200,也会因自定义头未被服务端允许被拦截。
注:Postman、reqbin等API测试工具是服务端发起请求,不受浏览器同源策略限制,不会自动发送CORS预检请求,因此调用成功不能代表浏览器侧CORS配置符合要求。
修复方案
- 放通OPTIONS请求的鉴权校验:在Nginx配置中针对OPTIONS请求直接返回204无内容状态码,不转发到后端业务服务、不触发鉴权逻辑,参考配置如下:
location / { # 单独处理OPTIONS预检请求 if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Credentials true always; add_header Access-Control-Allow-Methods "OPTIONS, GET, POST, PUT, PATCH, DELETE" always; add_header Access-Control-Allow-Headers "Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type, Access-Token" always; add_header Content-Length 0 always; add_header Content-Type text/plain always; return 204; } # 原有反向代理、业务路由配置 }
- 修正跨域允许源配置:不要写死固定的localtunnel域名,开发环境直接读取请求头中的
Origin值作为Access-Control-Allow-Origin的返回值即可;注意开启Access-Control-Allow-Credentials: true时,不能使用通配符*作为允许源,必须返回具体的源地址,同时排查配置中重复拼接Origin的逻辑,避免出现多个源值拼接的情况。 - 补全允许请求头列表:在
Access-Control-Allow-Headers配置中新增前端传递的自定义头Access-Token,确保自定义头被服务端认可。
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

