美文网首页SpringBoot精选Spring Boot
SpringBoot 全家桶 | WebSocket服务端与客户

SpringBoot 全家桶 | WebSocket服务端与客户

作者: 码农StayUp | 来源:发表于2020-08-16 00:29 被阅读0次

    本文源码:Gitee·点这里

    介绍

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

    WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

    参考

    1. Spring Framework 中文文档

    2. WebSocket 在线测试 v13

    3. HTML5 WebSocket

    Server端

    Server端我们使用SpringBoot的一个包spring-boot-starter-websocket,我们来引入它

    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    
    WebSocket处理器

    WebSocket处理器用来处理客户端发送的消息,Spring中常用的是两个TextWebSocketHandlerBinaryWebSocketHandler,我们使用TextWebSocketHandler

    import org.springframework.web.socket.handler.TextWebSocketHandler;
    ​
    public class ChatWebSocketHandler extends TextWebSocketHandler {
    ​
     @Override
     public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    
     }
    ​
     @Override
     protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
     String msg = message.getPayload();
     }
    
     @Override
     public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    
     }
    
     @Override
     public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    
     }
    }
    

    重写TextWebSocketHandler的四个方法:

    • afterConnectionEstablished 成功创建连接后调用

    • handleTextMessage 收到客户端消息后调用

    • handleTransportError 连接异常时调用

    • afterConnectionClosed 连接关闭后调用

    WebSocketSession是客户端与服务端建立的回话,可以通过close()方法主动关闭连接

    TextMessage为收到的消息,可以通过getPayload()方法获取消息内容

    WebSocket配置

    有了处理器了,就可以将此处理器映射到指定path上了,这需要增加一些配置,Spring提供一个配置接口WebSocketConfigurer,我们来实现它,并启用@EnableWebSocket

    import org.springframework.web.socket.config.annotation.EnableWebSocket;
    import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
    ​
    @Configuration
    @EnableWebSocket
    public class WebSocketConfig implements WebSocketConfigurer {
    ​
     /**
     * 用于将WebSocket处理程序映射到特定URL
     *
     * @param registry
     */
     @Override
     public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
     registry.addHandler(chatWebSocketHandler(), "chat") // 添加消息处理器
     .setAllowedOrigins("*"); // 设置跨域
     }
    
     /**
     * 自定义消息处理器
     *
     * @return
     */
     @Bean
     public ChatWebSocketHandler chatWebSocketHandler() {
     return new ChatWebSocketHandler();
     }
    ​
    }
    

    重写registerWebSocketHandlers方法,通过registry.addHandler()将消息处理器添加,并指定映射的path,服务端WebSocket地址为 ws://host:port/path

    注:需要注意的一点,这里要设置跨域,使用setAllowedOrigins方法即可。

    至此WebSocket的服务端就可以使用了,还有一些其他骚操作继续往下看

    WebSocket握手拦截器

    在建立连接前,我们可以通过握手拦截器来拦截非法请求,需要实现SpringHandshakeInterceptor接口

    import org.springframework.web.socket.server.HandshakeInterceptor;
    ​
    public class ChatHandshakeInterceptor implements HandshakeInterceptor {
    ​
     private final Logger log = LoggerFactory.getLogger(this.getClass());
    ​
     @Override
     public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
     log.info("--------------握手前拦截");
     return true;
     }
    ​
     @Override
     public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
     log.info("--------------完成握手");
     }
    }
    

    实现两个方法:

    • beforeHandshake握手前,该方法返回true表示继续建立连接,返回false则终止

    • afterHandshake握手后

    WebSocketConfig配置文件增加

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
     registry.addHandler(chatWebSocketHandler(), "chat") // 添加消息处理器
     .addInterceptors(chatHandshakeInterceptor()) // 添加握手拦截器
     .setAllowedOrigins("*"); // 设置跨域
    }
    /**
     * 自定义消息拦截器
     *
     * @return
     */
    @Bean
    public ChatHandshakeInterceptor chatHandshakeInterceptor() {
     return new ChatHandshakeInterceptor();
    }
    
    Session空闲失效时间配置

    一个会话连接后不可能一直不断开,这需要增加一些配置来约束超时时间;还可以设置消息缓冲区大小等(如果Nginx中配置了超时时间,此处可以忽略),上代码

    WebSocketConfig配置文件增加

    /**
     * 其他配置,如session空闲失效时间,消息缓冲区大小
     *
     * @return
     */
    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
     ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
     container.setMaxTextMessageBufferSize(8192);
     container.setMaxSessionIdleTimeout(10 * 60 * 1000L);
     return container;
    }
    
    Nginx配置

    大部分服务器都使用了Nginx代理,那么需要增加一些配置来支持WS协议

    # 支持WS协议
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    ​
    # 会话超时时间
    proxy_connect_timeout 620;
    proxy_send_timeout 620;
    proxy_read_timeout 620;
    

    Client端

    浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

    创建WebSocket连接

    连接协议使用wspath为服务端消息处理器映射的path

    var ws = new WebSocket("ws://127.0.0.1:8080/chat");
    
    WebSocket事件与方法
    if (typeof (WebSocket) == "undefined") {
        alert("您的浏览器不支持WebSocket")
        return
    }
    
    // 打开一个 web socket
    var ws = new WebSocket("ws://127.0.0.1:8080/chat");
    
    ws.onopen = function()
    {
        // Web Socket 已连接上,使用 send() 方法发送数据
        ws.send("发送数据");
        alert("数据发送中...");
    };
    
    ws.onmessage = function (evt) 
    { 
        var received_msg = evt.data;
        alert("数据已接收...");
    };
    
    ws.onclose = function()
    { 
        // 关闭 websocket
        alert("连接已关闭..."); 
    };
    
    ws.onerror = function () {
        // 连接错误
        alert("连接错误..."); 
        ws.close();
    }
    
    

    四个监听事件

    • onopen 与服务端连接成功

    • onmessage 接收服务端发送的消息

    • onclose 连接关闭

    • onerror 连接异常

    两个方法

    • send() 向服务端发送消息

    • close()关闭与服务端的连接

    聊天Demo演示

    本demo简单实现用户A向用户B发送消息,用户B也可以回复消息,具体内容请移步我的码云!

    demo.png

    完整代码

    springboot-websocket

    timg (2).jpg

    相关文章

      网友评论

        本文标题:SpringBoot 全家桶 | WebSocket服务端与客户

        本文链接:https://www.haomeiwen.com/subject/jywzdktx.html