【问题标题】:Angular + Spring boot Websocket cors errorAngular + Spring boot Websocket cors错误
【发布时间】:2021-11-09 10:09:53
【问题描述】:

我正在使用 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 boot 的后端我有以下 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) { }
}

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

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

使用逻辑定义为休息控制器的休息点完美地工作

提前致谢

如果我像这样更改 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();
    }

我遇到同样的错误

修复

我将 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") 在配置中。现在我必须弄清楚如何为所有不同的环境配置它,而不仅仅是本地

【问题讨论】:

  • 整个问题都明确写在错误信息中。你不能在这里使用allow-origin: * 通配符模式。您应该明确设置可以访问您的端点的来源。您可以在此处设置 http://localhost:4200 或 request->headers->origin and cors 错误应该消失
  • 其余请求是在无凭据模式下发出的。在这种模式下,允许使用通配符。但是 sockjs 发出请求时包含凭据,因此不能使用通配符
  • 您还应该添加凭据标头。按照错误中的描述更改原点,并在收到其他错误消息时遵循它们
  • 错误 stTes 清楚表明使用凭据时它不能是 woldcard

标签: angular spring-boot websocket cors


【解决方案1】:

修复

我将 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") 在配置中。现在我必须弄清楚如何为所有不同的环境配置它,而不仅仅是本地

【讨论】:

    【解决方案2】:

    修复

    我将 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,或者在字符串数组中添加来自localhost的所有origings appart)

    【讨论】:

      猜你喜欢
      • 2021-06-14
      • 2020-11-05
      • 2020-02-07
      • 1970-01-01
      • 1970-01-01
      • 2020-09-08
      • 2020-05-02
      • 2020-07-02
      • 1970-01-01
      相关资源
      最近更新 更多