在做前端页面渲染时,经常会遇到有的组件需要跟随数据的变化而实时的变化,例如:一个线上报名系统,总人数有一定限制,所以要实时的展现已经报名的人数,应该怎么实现呢?最基本有如下3种方案:
- Ajax轮询
- Ajax长轮询(comet)
- websocket长连接
Ajax轮询
优点
实现简单,利用XHR,通过setInterval定时向后端发送请求。
缺点
会造成数据在一小段时间内不同步和大量无效的请求,增加后端处理压力.
1 | setInterval(function() { |
Ajax长轮询(comet)
在Ajax轮询的基础上做的一点改进,在后端数据没有更新的时候不再返回空响应,而且后端一直保存连接,直到后端有数据变化,则相应请求并且关闭连接,前端收到数据,马上再次向后端发起请求,并处理刚刚收到的数据。
通常的做法是,在服务器的程序中加入一个死循环,在循环中监测数据的变动。当发现新数据时,立即将其输出给浏览器并断开连接,浏览器在收到数据后,再次发起请求以进入下一个周期。
1 | function async() { |
websocket长连接
WebSocket是html5中的协议,支持持久连接。http协议不支持持久连接,http1.0和http1.x都不支持持久性连接,http1.1中的keep-alive将多个http请求合并为1个。
WebSocket通信协议包含两个部分,一是开放性HTTP握手连接协商连接参数,二是二进制消息分帧机制(接收消息的文本和二进制数据传输)。它是一个独立完善的协议,也可以在浏览器之外实现。
HTTP的生命周期通过Request来界定,也就是Request一个response,那么在http1.0协议中这次请求就结束了;在http1.1中进行了改进,是有一个connection:keep-alive,也就是说在一个http连接里可以发送多个request,接收多个response。
Websocket是基于http协议的,或者说借用了http协议来完成部分握手,在握手阶段和http是相同的,请求头中多了两个属性:upgrade,connection
1
2Upgrade: websocket
Connection: Upgrade
HTTP升级协商
WebSocket协议提供了很多强大的特性:基于消息的通信、自定义的二进制分帧层、子协议协商、可选的协议扩展,等等。即在交换数据之前,客户端必须与服务器协商适当的参数以建立连接。
利用HTTP完成握手有几个好处。首先,让WebSockets与现有HTTP基础设施兼容:WebSocket服务器可以运行在80和443 端口上,这通常是对客户端唯一开放的端口。其次,让我们可以重用并扩展HTTP的Upgrade流,为其添加自定义的WebSocket首部,以完成协商。
请求头信息
Connection:Upgrade Sec-WebSocket-Key:eDCPPyPQZq7PiwRcx8SPog== Sec-WebSocket-Version:13 Upgrade:websocket
响应头信息
HTTP/1.1 101 Switching Protocols Connection:Upgrade Sec-WebSocket-Accept:/ZVAP3n6XuqDUoDp416PYUO+ZJc= Upgrade:websocket
最后,前述握手完成后,如果握手成功,该连接就可以用作双向通信信道交换WebSocket消息。到此,客户端与服务器之间不会再发生HTTP通信,一切由WebSocket 协议接管。
具体使用方法,本文采用node.js中的Socket.IO来进行说明:
- 服务端创建socket.io的实例
1 | var app = require('express')(); |
- 数据传输
1 | // 前端客户端向后端发送数据: |