我有一台OpenShift Wildfly服务器。我正在使用Spring MVC
框架构建一个网站。我的一个网页也使用WebSocket连接。在服务器端,我使用了@ServerEndpoint
注释和javax.websocket.*
库来创建我的websocket:
package com.myapp.spring.web.controller;
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.web.socket.server.standard.SpringConfigurator;
@ServerEndpoint(value="/serverendpoint", configurator = SpringConfigurator.class)
public class serverendpoint {
@OnOpen
public void handleOpen () {
System.out.println("JAVA: Client is now connected...");
}
@OnMessage
public String handleMessage (Session session, String message) throws IOException {
if (message.equals("ping")) {
// return "pong"
session.getBasicRemote().sendText("pong");
}
else if (message.equals("close")) {
handleClose();
return null;
}
System.out.println("JAVA: Received from client: "+ message);
MyClass mc = new MyClass(message);
String res = mc.action();
session.getBasicRemote().sendText(res);
return res;
}
@OnClose
public void handleClose() {
System.out.println("JAVA: Client is now disconnected...");
}
@OnError
public void handleError (Throwable t) {
t.printStackTrace();
}
}
OpenShift提供了一个默认URL,因此我的所有网页(html文件)都有公共(规范)主机名。为简单起见,我将此网址称为URL A
( projectname-domainname.rhclound.com
)。我创建了URL A
的别名CNAME,名为URL B
(例如 https://www.mywebsite.tech
)。 URL B
是安全的,因为它有https
。
我正在使用JavaScript客户端连接到路径/serverendpoint
上的WebSocket。我在html网页文件test.html
中使用的URI如下:
var wsUri = "wss://" + "projectname-domainname.rhclound.com" + ":8443" + "/serverendpoint";
当我打开URL A
( projectname-domainname.rhclound.com/test
)时,WebSocket会连接,一切正常。但是,当我尝试使用URL B
( https://mywebsite.tech/test
)连接到websocket时,JavaScript客户端会立即连接并断开连接。
以下是我收到的来自控制台的消息:
这是我连接到WebSocket的JavaScript代码:
/****** BEGIN WEBSOCKET ******/
var connectedToWebSocket = false;
var responseMessage = '';
var webSocket = null;
function initWS() {
connectedToWebSocket = false;
var wsUri = "wss://" + "projectname-domainname.rhcloud.com" + ":8443" + "/serverendpoint";
webSocket = new WebSocket(wsUri); // Create a new instance of WebSocket using usUri
webSocket.onopen = function(message) {
processOpen(message);
};
webSocket.onmessage = function(message) {
responseMessage = message.data;
if (responseMessage !== "pong") { // Ping-pong messages to keep a persistent connection between server and client
processResponse(responseMessage);
}
return false;
};
webSocket.onclose = function(message) {
processClose(message);
};
webSocket.onerror = function(message) {
processError(message);
};
console.log("Exiting initWS()");
}
initWS(); //Connect to websocket
function processOpen(message) {
connectedToWebSocket = true;
console.log("JS: Server Connected..."+message);
}
function sendMessage(toServer) { // Send message to server
if (toServer != "close") {
webSocket.send(toServer);
} else {
webSocket.close();
}
}
function processClose(message) {
connectedToWebSocket = false;
console.log("JS: Client disconnected..."+message);
}
function processError(message) {
userInfo("An error occurred. Please contact for assistance", true, true);
}
setInterval(function() {
if (connectedToWebSocket) {
webSocket.send("ping");
}
}, 4000); // Send ping-pong message to server
/****** END WEBSOCKET ******/
经过大量的调试和尝试各种各样的事情,我得出结论,由于Spring Framework,这就出现了问题。 这是因为在我的项目中引入Spring Framework
之前,URL B
可以连接到WebSocket,但是在介绍Spring之后,它不能。
我在spring's website上阅读了关于WebSocket政策的内容。我遇到了same origin policy,它们声明别名URL B
无法连接到WebSocket,因为它与URL A
的原点不同。为了解决这个问题,我在文档中说了disabled the same origin policy with WebSockets,所以我添加了以下代码。我认为这样做可以解决我的错误。这是我添加的内容:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
但是,这并没有解决问题,因此我将以下方法添加到我的ApplicationConfig
extends WebMvcConfigurerAdapter
:
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("https://www.mywebsite.com");
}
这也没有用。然后我尝试了这个:
package com.myapp.spring.security.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class MyCorsFilter {
// @Bean
// public FilterRegistrationBean corsFilter() {
// System.out.println("Filchain");
// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// CorsConfiguration config = new CorsConfiguration();
// config.setAllowCredentials(true);
// config.addAllowedOrigin("https://www.mymt.tech");
// config.addAllowedHeader("*");
// config.addAllowedMethod("*");
// source.registerCorsConfiguration("/**", config);
// FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
// bean.setOrder(0);
// System.out.println("Filchain");
// return bean;
// }
@Bean
public CorsFilter corsFilter() {
System.out.println("Filchain");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // you USUALLY want this
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
System.out.println("Filchain");
return new CorsFilter(source);
}
}
这也行不通。
我甚至将JS代码中的var wsURI
更改为以下内容:
var wsUri = "wss://" + "www.mywebsite.com" + ":8443" + "/serverendpoint";
然后var wsUri = "wss://" + "mywebsite.com" + ":8443" + "/serverendpoint";
当我这样做时,谷歌Chrome给了我一个错误,说握手失败了。但是,当我有这个URL var wsUri = "wss://" + "projectname-domianname.rhcloud.com" + ":8443" + "/serverendpoint";
时,我没有收到握手没有发生的错误,但是我收到一条消息,表明连接立即打开和关闭(如上所示)。
那么我该如何解决这个问题呢?
答案 0 :(得分:0)
您是否尝试实现WebMvcConfigurer
并重写方法addCorsMappings()
?如果没有,请尝试看看。
@EnableWebMvc
@Configuration
@ComponentScan
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST")
.allowedHeaders("Origin", "Accept", "Content-Type", "Authorization")
.allowCredentials(true)
.maxAge(3600);
}
}
答案 1 :(得分:0)
我不认为这是 CORS 问题,因为它在断开连接之前已成功连接。如果是 CORS,您甚至无法连接。
我认为这是您的 DNS 和 openshift 之间的通信问题,因为 WebSocket 需要一个持久连接(长寿命),该连接在客户端和服务器之间保持打开状态。如果您的 DNS(例如 CloudFlare 或类似的东西)不支持/未配置为使用 WebSocket,则客户端将像您的问题一样立即断开连接。