Spring WebSocket踩坑指南

Spring WebSocket踩坑指南

本次公司项目中需要在后台与安卓App间建立一个长连接,这里采用了Spring的WebSocket,协议为Stomp。
关于Stomp协议这里就不多介绍了,网上一搜一大把,这里主要说下在配置过程的踩过的那些坑。

官网才是首选

首先在我们第一次尝试WebSocket肯定会搜寻各种各样的博客,在看完关于Stomp和长连接的基础知识,确定使用Spring WebSocket后,请马上进入官网Spring WebSocket,并下载该网站右侧的源码,这将节省大量时间。网上的各个博客都是对官网的一定翻译而已,重复性的内容过多,直接阅读官网就好。接下来就是一步步排雷组装到自己的项目中了。
正因为官网的存在,本篇文章只讲踩坑,配置步骤详见官网文档与源码。

依赖

    <!-- stomp协议websocket长连接 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
        <!-- 该部分的版本号一般与当前项目的Spring版本号一致即可 -->
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-messaging</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- 长连接中消息的传递使用JSON格式,
    该依赖帮助Spring自动在Object与JSON之间转换,
    不加的话会在传递消息时报错-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.5.3</version>
    </dependency>
    <dependency>
      <groupId>javax.websocket</groupId>
      <artifactId>javax.websocket-api</artifactId>
      <version>1.1</version>
      <scope>provided</scope>
    </dependency>

spring扫描问题

在项目配置过程中,我出现了客户端无法向服务器发送请求的错误。事实上服务器已经收到了请求,此时打印日志:
No matching message handler methods.
此时我们的目标是客户端向服务器的指定接口发送数据,日志的意思为服务器已经接收到消息但没有合适的方法去处理它。这是因为在所需处理的方法上的注解@Message并没有被Spring MVC扫描到。在Spring Boot中不会出现这个问题,但在Spring MVC中可以查看配置文件spring-mvc.xml中在组件扫描中是否加入了use-default-filters="false"。use-default-filters="true"为默认配置,即允许Spring扫描配置包下的所有组件;而设为false后仅允许Spring控制网站的跳转逻辑,忽略了@Message注解。删除即可。

web.xml 3.0

Java Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container

报错很清晰了,请将web.xml从2.0修改为3.0,并在filter中加入配置<async-supported>true</async-supported>,作用是支持异步处理。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

302

这是在使用SockJS时出现的问题。这是因为我们项目中使用了Shiro作为权限管理,将所需暴露的接口配置一下即可。

https - wss 403

如果我们网站正式服务器采用了https协议,那么相对应的WebSocket的协议必须为wss。否则出现403问题。解决的另一种情况可以参见Nginx反向代理WebSocket响应403的解决办法,不过我没有使用它,也没有测过。

handshake: Unexpected response code: 400

这是由于正式服务器中采用了NGINX作为反向代理,这里需要更新下NGINX配置,具体如下:

    location /{
        proxy_pass        http://wsbackend;
        // 解决下面60s自动断开的问题
        proxy_read_timeout          600s;
        # WebSocket support (nginx 1.4),加入以下几行
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        }

}

WebSocket 60s自动断开连接

还是NGINX问题。解决方案已经在上面指出。proxy_read_timeout 默认为60s,如果NGINX对一个长连接在读取一次数据60s后没有再次接收到消息,则认为已超时,并关闭该连接,所以前端很准时的60s后开始报错。这里将时间修改到了10分钟,可以根据自己情况调整。

心跳

继续上面的话题,即使修改了超时时间为10分钟也没有实质性的改变,这时候心跳包就需要登场了。心跳包设计可以参考一种心跳,两种设计| 徐靖峰|个人博客高效保活长连接:手把手教你实现 自适应的心跳保活机制这两篇博客。第二篇博客更多关于安卓端。

安卓端SDK

这里我在GitHub上找了一个包:
'com.github.forresthopkinsa:StompProtocolAndroid:17.09.1'
具体见GitHub

安卓端进程防杀死补充

这部分可以参考FV悬浮球的说明。同时也推荐下这款软件,在安卓上的手势辅助功能很好用。

End.

猜你喜欢

转载自www.cnblogs.com/ykqfrost/p/10793740.html
今日推荐