springbootSpringboot

SpringBoot 集成 WebSocket

2019-01-20  本文已影响126人  JobanCai

官方地址:SpringBoot WebSockets
原作者地址:http://www.caijp.xyz/archives/springboot-websocket


webSocket 介绍

WebSocket协议RFC 6455提供了一种标准化的方式来建立一个全双工,客户端和服务器之间的双向通信信道在一个TCP连接。
WebSocket 交互始于一个HTTP请求,HTTP请求的header中携带Upgrade参数,对应的值是WebSocket,header中的Connection参数对应的值是Upgrade。

GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080 

服务端返回的通常不是200的状态码,而是服务端支持WebSocket的返回

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp

然后客户端将协议升级成为WebSocket,握手完成。

HTTP vs WebSocket

使用HTTP与其他应用程序的交互通常通过URL,服务器将请求路由到相应的处理程序是基于HTTP URL,method,和headers。
相比于HTTP, WebSockets通常只是有一个URL初始连接,随后所有应用程序消息流上同样的TCP连接。

SpringBoot 集成WebSocket Demo

1. maven 依赖

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

2.WebSocketHandler

SpringBoot 提供两种WebSocketHandler,TextWebSocketHandler 用于处理文本信息,BinaryWebSocketHandler用于处理二进制信息。session对象表示当前连接会话,session.sendMessage(new TextMessage("send message to current user"));向当前客户端发送消息

import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;

@Component
public class MyHandler extends TextWebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("Opened new session in instance " + this);
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        // ...
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.info("Info: WebSocket connection closed.");
    }

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

    }

}

3.WebSocketConfigurer

配置WebSocketHandler 映射到特定的URL,设置允许跨域,设置消息缓冲区大小,设置空闲连接超时时长

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private MyHandler myHandler;

    /**
     * sockJs 低版本浏览器不支持webSocket时使用
     * url结构:http://host:port/{endpoint}/{server-id}/{session-id}/websocket
     * 也可以: ws://host:port/{endpoint}/websocket
     * <p>
     * 不使用sockJs 访问时 url: ws://host:port/{endpoint}
     * <p>
     * setClientLibraryUrl 兼容客户端sockJs版本
     */
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
 
        registry.addHandler(myHandler, "/myHandler").setAllowedOrigins("*");
        registry.addHandler(myHandler, "/myHandler").setAllowedOrigins("*").withSockJS()
                .setTaskScheduler(sockJsScheduler()).setClientLibraryUrl("//cdn.jsdelivr.net/sockjs/1/sockjs.min.js");
    }

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        // ws 传输数据的时候,数据过大有时候会接收不到,所以在此处设置bufferSize
        container.setMaxTextMessageBufferSize(512000);
        container.setMaxBinaryMessageBufferSize(512000);
        container.setMaxSessionIdleTimeout(15 * 60000L);
        return container;
    }

}

4.WebSocket Handshake

通过集成HandshakeInterceptor,重写"before" 和 "after"的握手方法可以自定义HTTP和WebSocket的握手请求。例如,有一个内置的拦截器通过HTTP会话属性封装到WebSocket会话属性:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyHandler(), "/myHandler")
            .addInterceptors(new HttpSessionHandshakeInterceptor());
    }

}
@Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
            WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {

        HttpSession session = getSession(request);
        if (session != null) {
            if (isCopyHttpSessionId()) {
                attributes.put(HTTP_SESSION_ID_ATTR_NAME, session.getId());
            }
            Enumeration<String> names = session.getAttributeNames();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                if (isCopyAllAttributes() || getAttributeNames().contains(name)) {
                    attributes.put(name, session.getAttribute(name));
                }
            }
        }
        return true;
    }

5.Server config

每一个websocket 引擎都会暴露一些配置属性用于控制运行时的特性,比如说消息缓冲区的大小,空闲超时时长等等。
对于Tomcat来说,可以添加ServletServerContainerFactoryBean 到你的Websocket Java Config 来控制

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        container.setMaxTextMessageBufferSize(8192);
        container.setMaxBinaryMessageBufferSize(8192);
        container.setMaxSessionIdleTimeout(15 * 60000L);
        return container;
    }

}
上一篇下一篇

猜你喜欢

热点阅读