首先遇到这个问题有点奇葩,出现在项目上线时的客户现场,头两天一直都无法确定原因,因为它的表现方式很奇怪,基于springboot实现的websocket,同样的代码在公司研发环境不会有问题,客户现场会出现浏览器一连接就马上断开,没有使用任何代理服务器,服务器没有任何异常,就是浏览器直接断开,最后排除现场环境和公司环境差异性,不断保持两边的一直性,最有可能的一项,能想到的人不多了,IP地址不一样,我一开始是不相信的,IP地址不一样会导致这种问题?

我注重测试验证理论,试一把再说,结果就可以了,同样的服务器在192.168.x.x这种网段下不会有问题,如果是34.69.x.x这种短IP就不行,本人对网络不是很了解,同样的服务器和一模一样的代码,仅仅一个IP不同就会造成websocket无法使用吗?我知道的方法和网上的参考资料全部试了一下,无法解决,如果有知道的朋友可以留言。

此路不同就换一条路,我决定放弃springboot的websocket实现,尝试tomcat服务器的websocket实现,解决了此问题。

pom依赖:
<!-- SpringWebSocket依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</exclusion>
</exclusions>
</dependency>
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

java代码

import com.bootdo.common.utils.JSONUtils;
import com.bootdo.system.domain.UserDO;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint(value = "/endpointChat", configurator=GetHttpSessionConfigurator.class)
@Component
public class WebSocketSession {
private static final Logger logger = LoggerFactory.getLogger(WebSocketSession.class);
private static Map<String, WebSocketSession> clients = new ConcurrentHashMap<String, WebSocketSession>();
private Session session;
private String userSessionId;
private static String mark = "_";
private static String destinationPrefix = "/user";
private List<String> theme = new ArrayList<>();
@OnOpen
public void onOpen(Session session,EndpointConfig config) {
HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName()); SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) httpSession
.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
UserDO userDO = (UserDO) principalCollection.getPrimaryPrincipal(); session.setMaxTextMessageBufferSize(1024 * 100 * 5);
session.setMaxBinaryMessageBufferSize(1024 * 100 * 5);
this.userSessionId = userDO.getUserId().toString()+mark+session.getId();
this.session = session;
clients.put(this.userSessionId, this);
} @OnClose
public void onClose(Session session) {
try {
clients.remove(userSessionId);
}catch (Exception e){
logger.error(e.getMessage(),e);
}
} @OnError
public void onError(Session session, Throwable error) {
clients.remove(userSessionId);
try {
session.close();
} catch (IOException e) {
logger.error("close session failed {}", e.getMessage());
}
} /**
* 收到客户端消息后调用的方法
* @param message
*/
@OnMessage
public void onMessage(String message, Session session) {
SimpleTextMsg msgObj = JSONUtils.jsonToBean(message, SimpleTextMsg.class);
if(msgObj.getOption().equals(WebSocketClientOption.REGISTER_THEME)){//client在连接成功之后,注册监听主题
theme.add(msgObj.getTheme());
}
} public static void convertAndSendToUser(String userId, String theme, String jsonData) {
synchronized (userId.intern()){
try{
for (WebSocketSession item : clients.values()) {
String idKey = userId+mark+item.getUserSessionId().split(mark)[1];
if (item.getUserSessionId().equals(idKey)){
if(item.getTheme().contains(destinationPrefix+theme)){//判断该session的用户是否订阅主题
SimpleTextMsg textMsg = new SimpleTextMsg();
textMsg.setBody(jsonData);
textMsg.setTheme("/user"+theme);
item.session.getBasicRemote().sendText(JSONUtils.beanToJson(textMsg));
}
}
}
}catch (Exception e){
logger.error(e.getMessage(),e);
}
}
} public String getUserSessionId() {
return userSessionId;
} public void setUserSessionId(String userSessionId) {
this.userSessionId = userSessionId;
} public List<String> getTheme() {
return theme;
} public void setTheme(List<String> theme) {
this.theme = theme;
} public static Map<String, WebSocketSession> getClients() {
return clients;
}
}

html5_websocket.js 核心方法

//开始之前请引入reconnecting-websocket.js
var ipRe=/^(\d+)\.(\d+)\.(\d+)\.(\d+).*$/;//正则表达式
function SxpSockJS(url){
this.host = window.location.host; if(ipRe.test(url)){
this.url = url;
}else if(url.indexOf("http") == 0 || url.indexOf("https") == 0){
this.url = url.splice("//")[1];
}else{
this.url = this.host + url;
}
console.log("connection url:"+this.url);
this.websocket = null;
this.subscribe = function(theme, callBack){//theme订阅主题,callBack回调函数
this.websocket.themeMap[theme] = callBack;
this.websocket.send("{theme:'"+theme+"',option:'registerTheme'}");
};
this.connect = function(onOpen,onError){
this.websocket = new ReconnectingWebSocket("ws://"+this.url,null,{reconnectInterval: 3000});
this.websocket.themeMap = {};
this.websocket.timeoutInterval = 5400;
this.websocket.onopen = function(event){
console.log("漂亮!与服务器websocket连接成功!!!");
if(onOpen && typeof onOpen === "function")onOpen();
};
this.websocket.onclose = function(event){
console.log("悲剧!与服务器websocket连接断开!!!");
if(onError && typeof onOpen === "function")onError();
};
this.websocket.onmessage = function (data) {
console.log(data.timeStamp+"<<< CONNECTED");
var obj = eval('(' + data.data + ')');
var callBack = this.themeMap[obj.theme];
if(callBack){
console.log("theme:"+obj.theme);
console.log("jsonData:"+obj.body);
callBack(obj);
}
console.log(data.timeStamp+"<<< END");
console.log(" ");
}
}
}

js调用代码

        function init() {
var sock = new SxpSockJS(ctx+"endpointChat");
sock.connect(function() {//异步
sock.subscribe("/user/queue/prisoncellOnLine", handleNotification);
sock.subscribe("/user/queue/prisoncellAreaWarn", personAreaWarn);
sock.subscribe("/user/queue/prisoncellOffLine", personOffLine);
sock.subscribe("/user/queue/personSignEnd", personSignEnd);
sock.subscribe("/user/queue/personSignStart", personSignStart);
sock.subscribe("/user/queue/prisoncellFlush",prisoncellFlush);
},function(){
//异常处理逻辑
});
}

这里用到了一个websocket重连的函数,需要下载一个js,reconnecting-websocket.min.js

springboot的websocket因IP问题无法连接的更多相关文章

  1. 基于springboot的websocket聊天室

    WebSocket入门 1.概述 1.1 Http #http简介 HTTP是一个应用层协议,无状态的,端口号为80.主要的版本有1.0/1.1/2.0. #http1.0/1.1/2.0 1.HTT ...

  2. SpringBoot+Vue+WebSocket 实现在线聊天

    一.前言 本文将基于 SpringBoot + Vue + WebSocket 实现一个简单的在线聊天功能 页面如下: 在线体验地址:http://www.zhengqingya.com:8101 二 ...

  3. WebSocket的简单认识&SpringBoot整合websocket

    1. 什么是WebSocket?菜鸟对websocket的解释如下 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. WebSocket 使得客户端和服务 ...

  4. Springboot整合Websocket遇到的坑

    Springboot整合Websocket遇到的坑 一.使用Springboot内嵌的tomcat启动websocket 1.添加ServerEndpointExporter配置bean @Confi ...

  5. SpringBoot 整合 WebSocket

    SpringBoot 整合 WebSocket(topic广播) 1.什么是WebSocket WebSocket为游览器和服务器提供了双工异步通信的功能,即游览器可以向服务器发送消息,服务器也可以向 ...

  6. SpringBoot集成WebSocket【基于纯H5】进行点对点[一对一]和广播[一对多]实时推送

    代码全部复制,仅供自己学习用 1.环境搭建 因为在上一篇基于STOMP协议实现的WebSocket里已经有大概介绍过Web的基本情况了,所以在这篇就不多说了,我们直接进入正题吧,在SpringBoot ...

  7. SpringBoot基于websocket的网页聊天

    一.入门简介正常聊天程序需要使用消息组件ActiveMQ或者Kafka等,这里是一个Websocket入门程序. 有人有疑问这个技术有什么作用,为什么要有它?其实我们虽然有http协议,但是它有一个缺 ...

  8. springboot整合websocket原生版

    目录 HTTP缺点 HTTP websocket区别 websocket原理 使用场景 springboot整合websocket 环境准备 客户端连接 加入战队 微信公众号 主题 HTTP请求用于我 ...

  9. 使用springboot+layim+websocket实现webim

    使用springboot+layim+websocket实现webim 小白技术社   项目介绍 采用springboot和layim构建webim,使用websocket作为通讯协议,目前已经能够正 ...

  10. springboot集成websocket的两种实现方式

    WebSocket跟常规的http协议的区别和优缺点这里大概描述一下 一.websocket与http http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要有三次握手才能 ...

随机推荐

  1. .NET在单台Windows2008下百万TCP连接测试

    测试客户端: 客户端程序建立TCP连接,发送一条几个字节的数据. 虚拟机8台,PC机8台,服务器1台. 设置MaxUserPort=60000,有一台机没有设置约在1.5万左右.最后因为差一点到100 ...

  2. C#新语法

    C#新语法 NET6新特性以及C#新语法 1.顶级语句(C#9.0) (1):直接在C#文件中直接编写入口方法的代码,不用类,不用Main.经典写法仍然支持,反编译可以查看到,编译器依旧为我们生成了一 ...

  3. hive支持的压缩算法

    压缩格式的设置 set mapred.output.compression= 压缩格式 工具 算法 扩展名 是否支持分割 Hadoop编码/解码器 default deflate .deflate N ...

  4. 052_Lightning

    不支持内容: JavaScript buttons, customizable forecasting, and customizable tabs. 设置部分User选择使用Lightning: 单 ...

  5. 我眼中的Serverless

    https://cloud.tencent.com/document/product/583 摆脱服务器.存储等底层设备,只上传代码,由云服务器提供服务的触发,维护,调用.

  6. HTML实战:个人信息登记表

    效果展示: 代码示例: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  7. backward函数中gradient参数的一些理解

    当标量对向量求导时不需要该参数,但当向量对向量求导时,若不加上该参数则会报错,显示"grad can be implicitly created only for scalar output ...

  8. WKWebView与JS的交互

    转载:https://www.jianshu.com/p/253e76a74b38 用普通的UIWebView和JS交互 大概核心代码是这样的 - (void)setupWebView{ self.w ...

  9. linux 学习shell

    1. bash的父进程,子进程 [root@A~]# my_var=123[root@A~]# echo $my_var123[root@A~]# bash[root@A~]# [root@A~]# ...

  10. redis存储类型-数字和带双引号的数字

    这个是不一样的值,出现了转换异常