SpringBoot配置WebSocket

weixin_33866037發表於2018-07-28

簡介

WebSocket是一種在單個TCP連線上進行全雙工通訊的協議。WebSocket通訊協議於2011年被IETF定為標準RFC 6455,並由RFC7936補充規範。WebSocket API也被W3C定為標準。
WebSocket使得客戶端和伺服器之間的資料交換變得更加簡單,允許服務端主動向客戶端推送資料。在WebSocket API中,瀏覽器和伺服器只需要完成一次握手,兩者之間就直接可以建立永續性的連線,並進行雙向資料傳輸。

既然是一個長連線,那麼對於比較時效性(如聊天)或者需要推送的場景就可以使用WebSocket來實現,服務端不再是等待客戶端的請求而可以主動推送訊息給客戶端。同時也減少了資源的開銷,因為之前通過HTTP的做法通常都是輪詢來實現時效性,這種做法需要不斷髮起HTTP請求,而使用WebSocket長連線減少了連線的開銷,建立連線之後只關心資料本身。

基於SpringBoot的WebSocket支援

Spring Websocket介紹

Spring WebSocket通過註冊不同WebSocketHandler來處理不同的訊息通道,訊息處理具體在WebSocketHandler裡面實現,通常都是通過實現AbstractWebSocketHandler類來自定義自己的處理器。

maven依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

配置&使用

  • WebSocketConfig
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 註冊自定義訊息處理,訊息路徑為`/ws/foo`
        registry.addHandler(new FooWebSocketHandler(),"/ws/foo").setAllowedOrigins("*");

    }
}

  • 自定義處理器 FooWebSocketHandler
public class FooWebSocketHandler extends TextWebSocketHandler {

    private final static List<WebSocketSession> sessions = new ArrayList<>();

    public static List<WebSocketSession> allSessions(){
        return new ArrayList<>(sessions);
    }


    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //在這裡自定義訊息處理...
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        
        //儲存所有會話
        sessions.add(session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

        if(!sessions.isEmpty()){
            // remove session after closed
            for (Iterator<WebSocketSession> iterator = sessions.iterator();iterator.hasNext();){

                WebSocketSession s = iterator.next();

                if(session.getId().equals(s.getId())){
                    iterator.remove();
                }
            }
        }
    }
}
  • 實現簡單訊息推送給所有線上使用者
for (WebSocketSession session : FooWebSocketHandler.allSessions()) {
    try {
        TextMessage message = new TextMessage("${message body}").getBytes());
        if(session.isOpen()){
            session.sendMessage(message);
        }
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(),e);
    }
}
  • 客戶端與服務端連線互動(JavaScript為例)
var ws = new WebSocket('ws://localhost:8080/ws/foo')

ws.onmessage = function(event) {
  var data = event.data;
  console.log(data)
};
  • nginx配置WebSocket方向代理
http {

    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    upstream websocket {
        server localhost:8080;
    }
    
    server{
        location ~ /ws {
            proxy_pass http://websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }
}

參考

相關文章