springboot的websocket因IP問題無法連接


首先遇到這個問題有點奇葩,出現在項目上線時的客戶現場,頭兩天一直都無法確定原因,因為它的表現方式很奇怪,基於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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM