含凭证请求CORS通配符*报错,客户端如何解决?
问题详情
遇到如下CORS错误:
Access to XMLHttpRequest at 'https://my.domain/api/chat/info?t=1701325904808' from origin 'http://localhost:8100' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
chatItemMessage.page.ts:40 GET https://my.domain/api/chat/info?t=1701325904808 net::ERR_FAILED 200 (OK)
对接使用SockJS的Spring Boot后端,安装了以下依赖:
npm install sockjs-client npm install stompjs
编写了AppHttpInterceptor用于添加请求头,但上述GET请求从未触发该拦截器,拦截器代码如下:
@Injectable() export class AppHttpInterceptor implements HttpInterceptor { constructor(protected authService: AuthService, private router: Router) { } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return from(this.authService.getToken()).pipe( switchMap((token) => { const tokenString: string = token as string; if(token) { let authReq = req.clone({ setHeaders: { 'x-auth-token': tokenString, 'Content-Type': 'application/json' } }); return next.handle(authReq); } else { return next.handle(req); } }) ); } }
当前WebSocket连接代码:
const socket = new SockJS('https://my.domain/api/chat'); const stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { alert('connected StompClient in chatItemMessage.page.ts'); });
需求:寻找客户端侧的解决办法,同时解决拦截器未触发的问题。
客户端侧解决方案
1. 拦截器未触发的原因与修复
Angular的HttpInterceptor仅拦截Angular HttpClient发起的请求,而SockJS内部使用原生XMLHttpRequest/fetch发起请求,不会走Angular的拦截器链。需要手动给SockJS配置请求头:
// 先获取token(注意如果是异步方法要加await) const token = await authService.getToken(); const socket = new SockJS('https://my.domain/api/chat', {}, { transports: ['xhr-streaming', 'xhr-polling'], // 指定用XMLHttpRequest传输 headers: { 'x-auth-token': token, 'Content-Type': 'application/json' }, withCredentials: true // 根据需求决定是否开启,开启后后端不能用*作为允许源 }); const stompClient = Stomp.over(socket); // 也可以在stomp连接时额外携带header stompClient.connect({'x-auth-token': token}, function(frame) { alert('connected StompClient in chatItemMessage.page.ts'); });
2. CORS错误的针对性调整
根据错误提示,有两种客户端调整方向:
- 无需携带凭证时:关闭
withCredentials,此时后端用*作为Access-Control-Allow-Origin是合法的:const socket = new SockJS('https://my.domain/api/chat', {}, { withCredentials: false }); - 必须携带凭证时:客户端无法绕过限制,只能要求后端将
Access-Control-Allow-Origin设置为具体源(如http://localhost:8100),同时添加Access-Control-Allow-Credentials: true响应头。
3. 开发环境本地代理方案
开发阶段可以通过Angular代理绕过CORS:
- 项目根目录创建
proxy.conf.json:
{ "/api": { "target": "https://my.domain", "secure": true, "changeOrigin": true, "pathRewrite": { "^/api": "/api" } } }
- 修改
angular.json的serve配置,添加代理引用:
"serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "你的项目名:build", "proxyConfig": "proxy.conf.json" } }
- 修改WebSocket连接地址为本地代理路径:
const socket = new SockJS('/api/chat');
内容的提问来源于stack exchange,提问作者quma

