背景
最近,公司在开发一款主动服务机器人,将产生的消息数据通过服务端推送到客户端(H5、iOS、Android);同时支持用户进行提问,通过 NLP 识别用户意图,然后找到答案并回答用户。本次仅记录在进行部署主动服务通信服务时遇到的问题。
服务器向 Web 页面推送消息的方式
- 非阻塞轮询(短轮询):客户端以固定的频率(比如10秒钟一次)向服务端发送请求,如果服务端没有数据响应,就直接响应一个空,如果有数据响应,就将响应数据作为结果返回给客户端。特点是每次请求后,都会立即给响应。
- 阻塞长轮询(长轮询):客户端像传统轮询一样从服务器请求数据。如果服务器没有可以立即返回给客户端的数据,则不会立刻返回一个空结果,而是保持这个请求等待数据到来(请求阻塞或者超时),等有响应数据之后将数据作为结果返回给客户端。特点是一次请求后直到有响应数据时才会给返回,否则阻塞等待。
轮询并不是最好的解决方案
短轮询
优点是实现逻辑简单,但是当间隔太短时,会有大量的请求发送到服务器,会对服务器负载造成影响;而间隔太长,业务数据的实时性得不到保证无效请求的数量多。在用户量较大的情况下,服务器负载较高。
长轮询
优点是消息实时性高,无消息的情况下不会进行频繁的请求;缺点是服务端维持和客户端的连接会消耗掉一部分资源。
WebSocket ,一种高效节能的双向通信机制来保证数据的实时传输
-
WebSocket 是 HTML5 一种新的协议(Web TCP)。它建立在 TCP 之上,实现了客户端和服务端全双工异步通信.
-
它和 HTTP 最大不同是:
WebSocket 是一种双向通信协议,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据;
WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。
服务端与客户端通信架构
技术选型
- socketio
- 前端 socket.io.js
- 服务端 Netty-SocketIO
- 基础框架 SpringBoot
客户端自动断开连接,怎么办?
在自己电脑上把服务端启动后,然后客户端之间进行交流发送消息没有任何问题,但是通过 Nginx 代理后,发现客户端自动断开连接。
确认HTTP 1.1 版本
通过查看 Nginx 的日志,发现 HTTP 协议为 1.0 版本,因为在HTTP1.0 中,客户端发送请求,服务器接收请求,双方建立连接,服务器响应资源,请求结束;而在HTTP 1.1中,客户端发出请求,服务端接收请求,双方建立连接,在服务端没有返回之前保持连接,当客户端再发送请求时,它会使用同一个连接。这一直继续到客户端或服务器端认为会话已经结束,其中一方中断连接。参考〈完整的配置 #1〉
增加 WebSocket 的配置
Nginx 通过在客户端和后端服务器之间建立起一条隧道来支持WebSocket。为了使 Nginx 可以将来自客户端的 Upgrade 请求发送给后端服务器,Upgrade 和 Connection 的头信息必须被显式的设置。参考〈完整的配置 #2〉
完整的配置
location / {
proxy_pass http://chat-server:31001/;
proxy_redirect off;
#1
proxy_http_version 1.1;
#2
proxy_set_header Upgrade $http_upgrade; #WebSocket配置
proxy_set_header Connection "upgrade"; #WebSocket配置
proxy_read_timeout 90;
}
问题总结
H5、iOS、Android 支持
-
iOS,Android 端的 WebView 绝大部分支持。
不支持的有:
iOS7 之前的手机(可以不用考虑),iOS7 是2013年9月发布的。 Android5.0 之前的手机,2015年3月发布的系统。
-
PC端浏览器
一些版本的浏览器不支持,大部分的发布时间在2012年之前的,其余主流浏览器都支持