socketIO拒絕連接后防止心跳(反復)重連


  • 場景

  創建SocketIOServer時利用 isAuthorized 做了身份驗證,當驗證失敗時返回false,雖然服務並沒有建立起來,但是前端會不斷進行輪詢,從而造成一定的資源浪費。

@Bean
    public SocketIOServer socketIOServer() {
        Configuration config = new Configuration();
        config.setHostname(host);
        config.setPort(port);
        config.setAuthorizationListener(new AuthorizationListener() {
            @Override
            public boolean isAuthorized(HandshakeData data) {
                //TODO 該處可以用來進行身份驗證
                log.info("id【"+data.getSingleUrlParam("id")+"】正在進行連接");
                return ("1").equals(data.getSingleUrlParam("id"))? false : true;
            }
        });
        return new SocketIOServer(config);
    }
17:20:46.676  INFO 22704 --- [ntLoopGroup-5-6] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:20:47.940  INFO 22704 --- [ntLoopGroup-5-7] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:20:49.774  INFO 22704 --- [ntLoopGroup-5-8] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:20:54.783  INFO 22704 --- [ntLoopGroup-5-9] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:21:00.098  INFO 22704 --- [tLoopGroup-5-10] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:21:05.108  INFO 22704 --- [tLoopGroup-5-11] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:21:10.419  INFO 22704 --- [tLoopGroup-5-12] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:21:15.429  INFO 22704 --- [tLoopGroup-5-13] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
  • 解決思路

  從問題的表象看,造成這個情況的原因是前端沒有關閉socket連接服務,由於socket服務並沒有建立,JAVA不存在可操作的對象,因此只能限定前端只進行一次握手嘗試,或者被拒絕后關閉socket服務。

  • 解決方案

  后來在https://www.w3cschool.cn/socket/socket-k49j2eia.html里找到了這樣一段代碼

socket.on('connect_error', (error) => {
  // ...
});

  完善后

socket.on('connect_error', (error) => {
  socket.close();
});

  或者

socket.on('connect_error', function(error) {
  socket.close();
});

 

  實測問題得到解決:

17:43:32.339  INFO 22704 --- [tLoopGroup-5-11] c.e.socketdemo.SocketdemoApplication     : id【1】正在進行連接
17:43:47.625  INFO 22704 --- [tLoopGroup-5-13] c.e.socketdemo.SocketdemoApplication     : id【2】正在進行連接

  可以看到 "1" 並沒有下像之前一樣每隔幾秒就進行一次嘗試。

  • 拓展

  隨着握手失敗的測試增加,socket每次心跳的時間也會延長,但即使是延長 依然是在10秒內進行頻繁請求。大部分項目的身份權限驗證都是要連接數據庫進行的,所以除了從前端進行努力, 也可以使用中間件進行非法用戶的記錄,然后直接拒絕。

 

  • 后續更正

  上文提到反復鏈接是心跳原因,后來觀察很可能是因為socket.io的握手機制導致的。socket.io在進行握手的時候默認采用的是polling輪詢機制進行的,當失敗時會持續發送握手請求。

  當然,也有一種新的解決方案,在socket.io官網中有這樣的代碼:

  By default, a long-polling connection is established first, then upgraded to “better” transports (like WebSocket). If you like to live dangerously, this part can be skipped:

const socket = io({
transports: ['websocket']
});

// on reconnection, reset the transports option, as the Websocket
// connection may have failed (caused by proxy, firewall, browser, ...)
socket.on('reconnect_attempt', () => {
socket.io.opts.transports = ['polling', 'websocket'];
});

 

 

const socket = io({
  transports: ['websocket']
});

  這一段代碼是申明使用websocket進行首次創建,建議如果想要放棄無法使用socket服務的用戶,就使用這種方式。下方的代碼是在js中,創建時聲明連接方式的代碼:

var socket =  io.connect('http://localhost:9010?clientid='+clientid,{transports:['websocket']});

  而下方的重連聲明又將polling設為了首個創建方式,如果再次遇到polling創建失敗的用戶,服務器將會持續受到長輪詢的請求轟炸。

socket.on('reconnect_attempt', () => {
 socket.io.opts.transports = ['polling', 'websocket'];
});

 

  如果有更好的方式,請聯系交流, qq465824201, 轉載請標明出處。


免責聲明!

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



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