与服务器保持连接的几种方式
在某些业务场景里,客户端需要和服务端保持即时通信,比如:实时告警, 股票走势, 系统资源占用情况等。
# ajax 轮询
最常见最简单的方式就是 ajax 轮询了
let updateTimer = setInterval(() => {
getData()
}, 30000)
2
3
这种方法尽量的模拟即时传输,但并非真正意义上的即时通讯,很有可能出现客户端请求时,服务端数据并未更新。或者服务端数据已更新,但客户端未发起请求(30 秒的时间窗口引发的问题)。导致多次请求资源浪费,效率低下。
# ajax 长轮询
这种方式还是基于 ajax 请求,不同之处在于客户端发送请求之后,如果没有数据返回,服务端会将请求 挂起(不断开连接)处理其他请求,直到有数据返回给客户端。然后客户端再次发起请求,以此循环。
这里需要注意两个点:
- 延长客户端请求超时时间
- HTTP1.0 需要设置 请求头 Connection:keep-alive 服务端收到该请求头之后知道这是一个长连接,在响应报文头中也添加 Connection:keep-alive
在 HTTP1.1 或更高版本中默认使用了 Connection:keep-alive 长连接。 注意这里的长连接指的是 TCP(连接层)的长连接,而不是 HTTP(应用层)
长轮询可以减少客户端的请求,降低无效的网络传输,保证每次请求都有数据返回。
缺点是无法处理高并发,当客户端请求量大,请求频繁时对服务器的处理能力要求较高。服务器一直保持连接会消耗资源,需要同时维护多个线程(或进程),服务器所能承载的 TCP 连接数是有上限的,这种轮询很容易把连接数打满。
# WebSocket
Websocket 协议与 HTTP 协议不同,它是一个建立在 TCP 协议上的全新协议,为了兼容 HTTP 握手规范,在握手阶段依然使用 HTTP 协议,握手完成之后,数据通过 TCP 通道进行传输。
WebSocket 数据传输是通过 frame(分片) 形式,一个消息可以分成几个片段传输。这样大数据可以分成一些小片段进行传输,不用考虑由于数据量大导致标志位不够的情况。也可以边生成数据边传递消息,提高传输效率。
示例:
// 创建WebSocket连接.
const socket = new WebSocket('ws://localhost:8080')
// 连接成功触发
socket.addEventListener('open', function(event) {
socket.send('Hello Server!')
})
// 监听消息
socket.addEventListener('message', function(event) {
console.log('Message from server ', event.data)
})
2
3
4
5
6
7
8
9
10
11
12
可以看出 URL 是以 ws: 开头,如果是对应的 HTTPS,则以 wss: 开头。WebSocket 使用 ws 或 wss 为统一资源标志符,其中 wss 表示在 TLS 之上的 Websocket。
下面是知乎的 wss 连接
从上面可以看出 WebSocket 和 http 的不同之处
Status Code:101。该状态码表示协议切换。服务器返回了 101 ,表示没有释放 TCP 连接。WebSoket 协议握手阶段还是依赖于 HTTP 协议,到数据传输阶段便切换协议。
只有 WebSocket 协议才有的字段。请求头:
- Sec-WebSocket-Extension:表示客户端协商的拓展特性。
- Sec-WebSocket-Key:是一个 Base64 encode 的密文,由浏览器随机生成,用来验证是否是 WebSocket 协议。
- Sec-WebSocket-Version:表示 WebSocket 协议版本。
响应头:
- Sec-WebSocket-Extension:表示服务端支持的拓展特性。
- Sec-WebSocket-Accept:与客户端的 Sec-WebSocket-Key 相对应,是经过服务器确认,加密过后的 Sec-WebSocket-Key。
优点:
双向通信。客户端和服务端双方都可以主动发起通讯。
没有同源限制。客户端可以与任意服务端通信,不存在跨域问题(某些大厂的在线客服,一系统对多网站)。
数据量轻,传输效率高。第一次连接时需要携带请求头,后面数据通信都不需要带请求头,减少了请求头的负荷。
缺点:
兼容性,WebSocket 只支持 IE10 及其以上版本。服务器长期维护长连接需要一定的成本,各个浏览器支持程度不一;
HTTP 生态下有大量的库和组件可用,WebSocket 则没有,遇到异常问题难以快速定位快速解决。
长连接受网络限制比较大,需要处理好重连。