带Authorization头的GET请求仅浏览器报错(CF API与Angular18)
问题概述
我们基于ColdFusion自研RestAPI,配置了以下CORS响应头:
cfheader (name="Access-Control-Allow-Origin", value="*"); cfheader (name="Access-Control-Allow-Headers", value="*"); cfheader (name="Access-Control-Allow-Methods", value="GET, POST, PUT, HEAD, OPTIONS"); cfheader (name="Access-Control-Allow-Credentials", value="true");
服务器已开放所有请求头和方法,Angular 18应用的登录接口(POST,无授权头)在Postman和浏览器中均正常,但登录成功后的GET请求出现差异:
- 不带Authorization头时:Postman和浏览器均返回200,正常响应
- 带有效Authorization令牌时:仅Postman能获取有效响应,浏览器的OPTIONS预飞行请求和后续GET请求均报500 CORS错误
我们对比两种请求的头信息几乎一致,疑惑为何浏览器与Postman表现不同,且添加任意自定义头都会触发问题。
相关代码
Angular 18拦截器代码
if (req.headers.has('no-auth')) { req = req.clone({ headers: req.headers.delete('no-auth', 'true'), setHeaders: { Accept: 'application/json' }, }); return next(req); } else { /* Token: */ let Token = localStorage.getItem('Token') ? localStorage.getItem('Token') : ''; const auth_headers = req.headers.set('Authorization', `${Token}`); // Clone the request and add the authorization header const authReq = req.clone({/*auth_headers*/}); return next(authReq); }
注:拦截器尚未完成
补充API配置(OPTIONS预飞行处理)
// Handle CORS preflight request if (cgi.request_method == "OPTIONS") { cfheader(name="Access-Control-Allow-Origin", value="http://localhost:4004"); cfheader(name="Access-Control-Allow-Headers", value="Content-Type, Authorization"); cfheader(name="Access-Control-Allow-Methods", value="GET, POST, PUT, DELETE, OPTIONS"); cfheader(name="Access-Control-Allow-Credentials", value="true"); cfheader(statuscode="200", statustext="OK"); cfexit(); } // Your actual API logic here cfheader(name="Access-Control-Allow-Origin", value="*"); cfheader(name="Access-Control-Allow-Headers", value="*"); cfheader(name="Access-Control-Allow-Methods", value="GET, POST, PUT, DELETE, OPTIONS"); cfheader(name="Access-Control-Allow-Credentials", value="true");
核心原因分析
CORS规则冲突:通配符与Credentials不兼容
浏览器严格遵循CORS规范:当Access-Control-Allow-Credentials设为true时,Access-Control-Allow-Origin不能使用通配符*,必须指定具体的前端源(如http://localhost:4004)。Postman作为非浏览器工具,不会强制校验这一规则,因此能正常响应。OPTIONS预飞行与实际请求的Origin不一致
当前配置中,OPTIONS预飞行请求返回的Access-Control-Allow-Origin是具体源http://localhost:4004,但实际API请求返回的是*,浏览器会判定这两个Origin不匹配,直接拦截请求并抛出CORS错误。拦截器代码的潜在问题
拦截器中克隆请求时注释掉了auth_headers参数(const authReq = req.clone({/*auth_headers*/});),导致修改后的Authorization头没有正确附加到请求中,可能引发后续的认证逻辑错误,间接导致500状态码。
修复方案
- 统一Origin配置:将所有请求(包括OPTIONS预飞行和实际API请求)的
Access-Control-Allow-Origin都设置为前端应用的具体源(如http://localhost:4004),彻底移除通配符*。 - 保持CORS头一致性:确保OPTIONS预飞行返回的
Access-Control-Allow-Headers、Access-Control-Allow-Methods与实际API请求的配置完全一致,避免浏览器判定规则冲突。 - 修复拦截器代码:正确传递修改后的请求头,将克隆请求的代码改为:
const authReq = req.clone({ headers: auth_headers });
内容的提问来源于stack exchange,提问作者uwe85

