服务器端推送技术总结
最近在做前端页面渲染的时候,有的组件需要跟随数据的变化而实时的变化,例如:一个线上报名系统,总人数有一定限制,所以要实时的展现已经报名的人数,应该怎么实现呢?最基本解决思路如下:
技术方案:
1.Ajax轮询
2.Ajax长轮询
3.WebSocket
Ajax轮询
实现简单,利用XHR,通过setInterval定时向后端发送请求,优点是,实现非常简单;缺点是会造成数据在一小段时间内不同步和大量无效的请求,增加后端处理压力.
setInterval(function() {
$.ajax({
url: 'https://www.baidu.com/',
success: function() {
//success code
}
});
}, 3000);
Ajax长轮询
在Ajax轮询的基础上做的一点改进,在后端数据没有更新的时候不再返回空响应,而且后端一直保存连接,直到后端有数据变化,则相应请求并且关闭连接,前端收到数据,马上再次向后端发起请求,并处理刚刚收到的数据.
function async() {
$.ajax({
url: 'http://api.3g.qq.com',
success: function() {
async();
//success code
}
});
}
WebSocket
WebSocket是html5出来的东西(协议),也就是说http协议没有变化,或者说没关系,但http是不支持久链接的,WebSocket其实是一个新协议,跟http协议基本没有关系,只是为了兼容现有浏览器的握手规范而已。
WebSocket
通信协议包含两个部分,一是开放性HTTP
握手连接协商连接参数,二是二进制消息分帧机制(接收消息的文本和二进制数据传输)。它是一个独立完善的协议,也可以在浏览器之外实现。
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来进行说明:
1.服务端创建socket.io的实例
var app = require('express')();
var http = require('http').Server(app);
//创建实例
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendfile('index.html');
});
//监听前端连接
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
前端创建websocket连接:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
2.数据传输
前端向后端发送数据:
socket.emit('chat message', $('#m').val());
后端接收数据:
io.on('connection', function(socket){
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
});
----------------------------------------------------------------------------------------------------------------------------------
后端向前端发送数据:
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
前端接收数据:
socket.on('chat message', function(msg){
console.log(msg);
});