大麦牛奶

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

首先遇到这个问题有点奇葩,出现在项目上线时的客户现场,头两天一直都无法确定原因,因为它的表现方式很奇怪,基于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

posted on 2019-09-09 16:26  大麦牛奶  阅读(4510)  评论(0编辑  收藏  举报
码云springboot2.0通用权限系统脚手架 https://gitee.com/shenxingping/XPBoot