You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 12对接Spring Boot WebSocket出现CORS跨域错误如何解决?

Spring Boot + Angular 12 WebSocket CORS问题及修复

问题背景

本地使用Spring Boot和Angular 12开发WebSocket功能,查阅大量教程后仍遇到CORS错误,其余普通REST接口跨域均正常。

前端代码

Angular端Socket连接代码如下,该代码在页面加载时初始化的组件中执行:

import { Injectable } from '@angular/core';
import { NotificationWebSocket } from '../model/NotificationWebSocket.model';
import {  Stomp } from '@stomp/stompjs';
import * as SockJS from 'sockjs-client';


@Injectable({
  providedIn: 'root'
})
export class WebsocketService{

  stompClient: any;
  webSocketEndPoint: string = 'http://localhost:8080/notification';
  topic : string = "/notifications/messages"

  constructor(){
    console.log("Initialize WebSocket Connection");
    let ws = new SockJS(this.webSocketEndPoint);
    this.stompClient = Stomp.over(ws);
    const _this = this;
        _this.stompClient.connect({}, function (frame : any) {
            _this.stompClient.subscribe(_this.topic, function (sdkEvent : any) {
                _this.onMessageReceived(sdkEvent);
            });
        },);
  }

  disconnect() {
      if (this.stompClient !== null) {
          this.stompClient.disconnect();
      }
      console.log("Disconnected");
  }

  onMessageReceived(message : NotificationWebSocket) {
      console.log("Message Recieved from Server :: " + message);
  }
}

后端初始配置

WebSocket核心配置

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/notification");
        config.setApplicationDestinationPrefixes("/wigstat");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/notifications").setAllowedOrigins( "*" ).withSockJS();
    }
}


@Controller
public class WebSockerSender {

    @Autowired
    private NotificationWebSocketAdapter notificationWebSocketAdapter;

    @MessageMapping("/updates")
    @SendTo("/notifications/messages")
    public NotificationWebSocket send(Notification notification) {
        return notificationWebSocketAdapter.fromEntityToWebSocket( notification );
    }
}

通用REST接口CORS过滤器

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        HttpServletRequest req = (HttpServletRequest) request;

        res.setHeader( "Access-Control-Allow-Origin", "*" );
        res.setHeader( "Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS" );
        res.setHeader( "Access-Control-Allow-Headers", "*" );

        // 预检请求直接返回成功
        if ( req.getMethod().equals("OPTIONS") ) {
            res.setHeader( "Access-Control-Max-Age", "86400" );
            res.setStatus( HttpServletResponse.SC_OK );
            return;
        }

        chain.doFilter( request, response );
    }

    @Override
    public void destroy() { }

    @Override
    public void init(FilterConfig filterConfig) { }
}

报错信息

运行前端后控制台报错如下:
报错截图

第一次修复尝试

分别修改CORS过滤器和WebSocket配置的允许源为前端本地地址,仍报相同错误:

// 过滤器修改
res.setHeader( "Access-Control-Allow-Origin", "http://localhost:4200" );
// WebSocket配置修改
@Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/notifications").setAllowedOrigins( "http://localhost:4200" ).withSockJS();
    }

最终有效修复方案

修改CORS过滤器逻辑,同时保持WebSocket配置的允许源为http://localhost:4200后问题解决:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        HttpServletRequest req = (HttpServletRequest) request;

        String origin = req.getHeader("Origin");
        res.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "*");
        res.setHeader( "Access-Control-Allow-Credentials", "true" );
        res.setHeader("Vary", "Origin");
        res.setHeader( "Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS" );
        res.setHeader( "Access-Control-Allow-Headers", "*" );

        // 预检请求直接返回成功
        if ( req.getMethod().equals("OPTIONS") ) {
            res.setHeader( "Access-Control-Max-Age", "86400" );
            res.setStatus( HttpServletResponse.SC_OK );
            return;
        }

        chain.doFilter( request, response );
    }

后续待优化问题

需要适配除本地开发环境外的所有不同部署环境的跨域配置。


内容的提问来源于stack exchange,提问作者Gabriel García Garrido

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 15:30:00