Angular + Spring 启动 Websocket cors 错误

Angular + Spring boot Websocket cors error

我正在使用 Spring boot 和 Angular 12 在本地开发一个 websocket。我已经阅读了很多教程,但我遇到了一个奇怪的 Cors 错误。

连接套接字的Angular代码如下:

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);
  }
}

此代码在页面加载时加载的组件中初始化

在spring启动的后端我有以下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 );
    }
}

如您所见,这是所有教程都显示的超级简单的配置。

为了正常休息端点的 CORS 目的,我在后端配置中有一个 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", "*" );

        // Just REPLY OK if request method is OPTIONS for CORS (pre-flight)
        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) { }
}

当我 运行 前端和我检查控制台日志时,我看到以下内容:

我不明白为什么我无法连接这个超级简单的配置。

用逻辑定义的 Rest enpoints 作为 rest 控制器工作得很好

提前致谢

如果我像这样更改 cors 过滤器或 websocket 配置

res.setHeader( "Access-Control-Allow-Origin", "http://localhost:4200" );

@Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/notifications").setAllowedOrigins( "http://localhost:4200" ).withSockJS();
    }

我得到同样的错误

FIX

我把cors过滤器改成了这个,还加了

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", "*" );

        // Just REPLY OK if request method is OPTIONS for CORS (pre-flight)
        if ( req.getMethod().equals("OPTIONS") ) {
            res.setHeader( "Access-Control-Max-Age", "86400" );
            res.setStatus( HttpServletResponse.SC_OK );
            return;
        }

        chain.doFilter( request, response );
    }

.setAllowedOrigins("http://localhost:4200") 在配置中。现在我必须弄清楚如何为所有不同的环境配置它,而不仅仅是在本地

修复

我将 cors 过滤器更改为此并添加

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", "*" );

        // Just REPLY OK if request method is OPTIONS for CORS (pre-flight)
        if ( req.getMethod().equals("OPTIONS") ) {
            res.setHeader( "Access-Control-Max-Age", "86400" );
            res.setStatus( HttpServletResponse.SC_OK );
            return;
        }

        chain.doFilter( request, response );
    }

.setAllowedOrigins("http://localhost:4200") 在配置中。现在我必须弄清楚如何为所有不同的环境配置它,而不仅仅是在本地(可能使用 @ConfigurationPropeties 或在字符串数组中添加来自本地主机的所有原始设备)

修复

我将 cors 过滤器更改为这个并添加

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", "*" );

        // Just REPLY OK if request method is OPTIONS for CORS (pre-flight)
        if ( req.getMethod().equals("OPTIONS") ) {
            res.setHeader( "Access-Control-Max-Age", "86400" );
            res.setStatus( HttpServletResponse.SC_OK );
            return;
        }

        chain.doFilter( request, response );
    }

setAllowedOrigins("http://localhost:4200") 在配置中。现在我必须弄清楚如何为所有不同的环境配置它,而不仅仅是在本地