Spring WebSocket 与 SockJS 连接到不同的域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30502943/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 00:36:43  来源:igfitidea点击:

Spring WebSocket Connecting with SockJS to a different domain

springwebsockethttp-status-code-403sockjs

提问by Sniady

WebSockets in Spring is a rather new topic that I;m tiring to find a bit more.

Spring 中的 WebSockets 是一个相当新的话题,我很累,想找到更多。

My problem is with connecting to a service from a different domain, I'm working on with Lineman building the front-end side and Spring Boot when doing the back-end side, with that I have these apps on two different ports : 8000 and 8080 on localhost.

我的问题是连接到来自不同域的服务,我正在与 Lineman 一起构建前端端和 Spring Boot 在后端端,我在两个不同的端口上安装了这些应用程序:8000 和本地主机上的 8080。

I had issues with the 'Access-Control-Allow-Origin' header but I have resolved it by adding a filter on the server side which added the allowed origin to the header. After this I started to get the following error on connection:

我遇到了“Access-Control-Allow-Origin”标头的问题,但我通过在服务器端添加一个过滤器来解决它,该过滤器将允许的原点添加到标头中。在此之后,我开始在连接时出现以下错误:

GET http://localhost:8080/socket/info 403 (Forbidden)
AbstractXHRObject._start @ sockjs-0.3.4.js:807
(anonymous function) @sockjs-0.3.4.js:841

I don't have Spring Security in the project so this is not an authorization issue, the error points to sockJS : that.xhr.send(payload); - where payload is never defined.I tried but couldn't find the root of the call where is may began.

我在项目中没有 Spring Security 所以这不是授权问题,错误指向 sockJS : that.xhr.send(payload); - 从未定义有效载荷的地方。我尝试过但找不到可能开始的调用的根。

I was thinking if I need to add some additional information to either SockJS and Stomp when setting the connection, but there is not much of examples and notes in both wiki pages of this tools.

我在想是否需要在设置连接时向 SockJS 和 Stomp 添加一些附加信息,但是在此工具的两个 wiki 页面中都没有太多示例和注释。

Bellow you will find the connection JS code.

波纹管你会发现连接JS代码。

var socket = new SockJS("http://localhost:8080/socket");
client = Stomp.over(socket);

client.connect({'login': BoatsGame.userName,
                    'passcode': 'guest'},
            function (frame) {
....

The Server Side has a MessageBroker configured :    


@Configuration
@EnableWebSocketMessageBroker
public class MessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {

@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
     ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
     container.setMaxTextMessageBufferSize(8192);
     container.setMaxBinaryMessageBufferSize(8192);
     return container;
}

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
     //config.enableStompBrokerRelay("/queue", "/topic");
     config.enableSimpleBroker("/queue", "/topic","/user");
     config.setApplicationDestinationPrefixes("/BoatBattleGame");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
    stompEndpointRegistry.addEndpoint("/socket").withSockJS();
}
}

I Also tried setting up a MessageHandler as it has the option to set OriginAllowe when configuring, but I'm not sure how it is connected to the broker.

我还尝试设置 MessageHandler,因为它可以在配置时选择设置 OriginAllowe,但我不确定它是如何连接到代理的。

Last think, this setup works correctly when running on one port.

最后想一想,这个设置在一个端口上运行时可以正常工作。

回答by Sniady

Jax's anwesr was correct :)

Jax 的回答是正确的 :)

The registerStompEndpoints method gives us the opportunity to set the Allowed Origins. We need to add it before the "withSockJs()" option.

registerStompEndpoints 方法让我们有机会设置 Allowed Origins。我们需要在“withSockJs()”选项之前添加它。

    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/BO/socket").setAllowedOrigins("*").withSockJS();
    }

回答by Mauro

To anyone getting to this ticket because of the 403 Forbidden answer when trying to connect through a SockJsClient to a different domain:

对于尝试通过 SockJsClient 连接到不同域时由于 403 Forbidden 答案而获得此票证的任何人:

The problem arises when trying to make a GET to the /info Url, as part of the handshaking. The response actually returns a 200 via WGET as well as via browser. Only through SockJsClient it doesn't work.

作为握手的一部分,尝试对 /info Url 进行 GET 时会出现问题。响应实际上通过 WGET 以及浏览器返回 200。只有通过 SockJsClient 它不起作用。

After trying different solutions, the only one that really fixed the issue is to write a class that implements Transport and InfoReceiver. In this way the developer can directly handle this part of the handshake. Basically you make the work in the executeInfoRequest() method:

在尝试了不同的解决方案后,唯一真正解决问题的方法是编写一个实现 Transport 和 InfoReceiver 的类。这样开发者就可以直接处理这部分的握手了。基本上你在 executeInfoRequest() 方法中工作:

@Override
public String executeInfoRequest(URI infoUrl, HttpHeaders headers) {
    HttpGet getRequest = new HttpGet(infoUrl); // eventually add headers here
    HttpClient client = HttpClients.createDefault();

    try {
        HttpResponse response = client.execute(getRequest);
        List<String> responseOutput = IOUtils.readLines(response.getEntity().getContent());

        return responseOutput.get(0);
    } catch (IOException ioe) {
        ...
    }
}

I defined TransportType.XHR as transport type.

我将 TransportType.XHR 定义为传输类型。

回答by Frithjof Schaefer

In my case, I had to add these configuarations to get SockJS / STOM to work with CORS:

就我而言,我必须添加这些配置才能让 SockJS / STOM 与 CORS 一起使用:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer
{
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(false)
                .maxAge(3600)
                .allowedHeaders("Accept", "Content-Type", "Origin", 
"Authorization", "X-Auth-Token")
                .exposedHeaders("X-Auth-Token", "Authorization")
                .allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS");
    }
}

回答by Fabrice Yopa

i found this solution by creating a Filter

我通过创建过滤器找到了这个解决方案

package com.diool.notif.config;

import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class SimpleCORSFilter implements Filter {

    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SimpleCORSFilter.class);
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("Initilisation du Middleware");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest requestToUse = (HttpServletRequest)servletRequest;
        HttpServletResponse responseToUse = (HttpServletResponse)servletResponse;

        responseToUse.setHeader("Access-Control-Allow-Origin",requestToUse.getHeader("Origin"));
        filterChain.doFilter(requestToUse,responseToUse);
    }

    @Override
    public void destroy() {

    }
}