websocket 断线问题

198 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

前言

上一篇中我们使用spring boot 的websocket模块和一部分客户端代码组成了一个websocket的小系统。但是在实际使用过程中却经常出现过一段事件就断线的问题。首先java代码中并没有发现异常,而客户端代码中也没有找到问题,后面查询良久发现是使用了nginx的原因。

websocket小记

websocket协议最大的特点就是服务器可以主动向客户端推送消息,客户端也可以主动向服务端推送消息。是属于真正的双向交互。另外的几个特点是

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

两个端只要建立一次握手连接之后就可以进行多次的通讯,而不必像http协议那样每次数据交互都需要进行三次握手。

nginx 和 websocket

在使用过程中我们通常会使用nginx来进行反向代理。此时java服务会在websocket连接一段时间后报出java.io.EOFException的异常。一开始以为是连接超过了nginx 连接的保持的最长时间,于是将这个keepalive时间调大,但是并没有解决问题。

由于nginx 本身是使用http协议,而我们的服务是使用websocket协议,怀疑是尽管我们实际使用了ws在进行连接,但是由于中间使用了nginx,使得协议出现了一些不兼容的问题,把http协议的一些配置带入到了本该是ws协议的连接中,因此需要将我们的协议进行升级

 location /face/websocket {
            proxy_pass http://127.0.0.1:8081;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
 }

为了让Nginx可以将来自客户端的Upgrade请求发送到后端服务器,Upgrade和Connection的头信息必须被显式的设置。那么连接的时候从而就可以解决断线的问题。