Web即时通讯:
即时通讯技术就是及时的将服务端数据的结果展示在客户端的view层的一种技术。
应用场景:
在不刷新页面的情况下,实时查看投票结果
支付完成后页面根据入库支付结果显示 “支付成功”
商场自拍机器扫码支付后进入自拍的页面
股票应用的价格及时更改
webIM,ChatRoom,等即时通通讯的聊天室应用等等......
即时通讯四种方式:
轮询、长轮询(comet)、长连接(SSE)、WebSocket。
它们大体可以分为两类,一种是在HTTP基础上实现的,包括短轮询、长轮询和长连接;另一种不是在HTTP基础上实现是,即WebSocket。下面分别对其进行简单的介绍。
【1】轮询
解释:前端(客户端)发起定时器的循环请求后台,后台(服务端)接到请求后返回响应信息的一种方式
setInterval(function() {
$.ajax({
type: "get",
url: '接口地址',
async: true,
data:{"type":pay_type,"orderid":order_id}
}).done(function (data) {
//do something
})
}, 10000);
适用于:适用于小型应用,或者同时在线人数较少的应用
优点:简单省时,后端程序编写比较容易(几乎不用做什么特殊处理)
缺点:不及时(得看定时器的间隔),消耗大 ( 服务器宽带和资源)
【2】长轮询(comet)
解释:上面轮询每发出一次请求就要新建一个Http请求,长轮询只启动一个HTTP请求,其连接的服务端会挂起此次连接,后端定时器去查询数据库有没有新消息,直到有新消息才返回响应信息,客户端处理完响应信息后再向服务器发送新的Http请求,以此类推。区别于轮询的就是没有新消息就不会发送新的请求
通俗理解就是把前端的定时器转移到了后端,但是能及时拿到结果
后端代码具体的不做详细介绍原理如下:
后端写sleep(秒) 睡眠挂起请求,就是把前端的定时器移动到了后端,
后端while循环,不停的问数据库有没有结果。
没有进入定时睡眠,有则跳出循环处理逻辑。
前端核心就是循环调用ajax(递归)
// 获取最新的投票结果
function get_vote() {
axios.request({
url: '/get_vote',
method: 'get'
}).then(function (response) {
// 判断后端的数据是否为空
if (response.data != '') {
// 获取到最新的数据do somethings
}
// 获取完数据后,再发送请求,看还有没有新数据生成
get_vote()
});
}
适用于:适用于小型应用,或者同时在线人数较少的应用
优点:可实现实时数据回传,长轮询和轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。
缺点:连接挂起也会导致资源的浪费(服务器压力大,频繁操作询问数据库有没有新结果)
【3】长连接(SSE)
SSE是HTML5新增的功能,SSE(sever-sent events)服务器端推送事件,是指服务器推送数据给客户端,而不是传统的请求响应模式。简单的说,就是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送“信息”。而SSE最大的特点就是可以实现只要服务器端数据有更新,就可以马上发送到客户端。
注:IE不支持
//php服务端代码无需其他框架和依赖
header('X-Accel-Buffering: no');
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
ob_end_clean();
ob_implicit_flush(1);
$id = 0;
while (1) {
$id += 1;
$data = [
"id" => $id,
"message" => '现在是北京时间' . date('Y-m-d H:i:s')
];
$str = '';
$str .= "id: {$id}" . PHP_EOL;
$str .= "event: message" . PHP_EOL;
$str .= "retry: 0" . PHP_EOL;
$str .= "data:" . json_encode($data) . PHP_EOL;
$str .= PHP_EOL;
echo $str;
sleep(3);
}
//node.js服务端代码
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Access-Control-Allow-Origin": "*" //允许跨域
});
var num =0;
var f = function(){
if(num===10){
res.end();
}else{
res.write("id: " + num + "\n");
res.write("data: " + num + "\n\n");
num++;
}
setTimeout(f,1000);
}
f();
//点前端代码进行兼容性检测
if(typeof(EventSource)!=="undefined"){
var source = new EventSource('/test/接口'); //指定路由发送
source.onmessage = function(e) {
//监听信息的传输
var data = JSON.parse(e.data),
origin = e.origin;
console.log(data);
//data 服务器端传回的数据
//origin服务器端URL的域名部分,有protocol,hostname,port
//lastEventId用来指定当前数据的序号.主要用来断线重连时数据的有效性
};
source.onerror = function(e) {
//当连接发生error时触发
console.log(e);
};
source.onopen = function(e) {
//当连接正式建立时触发
console.log(e);
};
}else{
console.log("不支持SSE");
}
优点:SSE和轮询,长轮询相比它不用处理很多请求,不用每次建立新连接,延迟较低;SSE和WebSocket相比,最大的优势是便利,服务端不需要其他的类库,开发难度较低。
缺点:如果客户端有很多,那就要保持很多长连接浏览器一直转圈,这会占用服务器大量内存和连接数
【4】websocket
阮一峰websocket
websocket 最大的特点就是可以双向通信
php需要用到框架workerman
前端代码
var ws = new WebSocket("wss://www.aaa.com:8282");
// 服务端主动推送消息时会触发这里的onmessage
ws.onmessage = function(e){
// json数据转换成js对象
var gateway = JSON.parse(e.data);
console.log(gateway);
//以下为gatewaywork的方式
switch(gateway.type){
// Events.php中返回的init类型的消息,将client_id发给后台进行uid绑定
case 'connect':
var data = {
"client_id":gateway.client,
'number':"BJ_AC_001_2-0"
};
$.ajax({
type:"POST",
url:"https://www.aaa/version_3/init_bind",
data:data,
});
break;
case 'bind_ok':
console.log("链接上");
break;
case 'print':
console.log("有新消息可以打印了");
break;
case'ping':
ws.send(JSON.stringify({
'type':'pong'
}));
default :
// alert(e.data);
}
};
websocket 最大的特点就是可以双向通信。这里可以使用.
ws.send()方法发送数据, 不过只能发送String和二进制. 这里,我们通常call 数据叫做 Frames. 他是数据发送的最小单元.包含数据的长度和数据内容.
下面就是前端给后台通信的几种常用的发送方式
socket.send("Hello server!");
socket.send(JSON.stringify({'msg': 'payload'}));
var buffer = new ArrayBuffer(128);
socket.send(buffer);
var intview = new Uint32Array(buffer);
socket.send(intview);
var blob = new Blob([buffer]);
socket.send(blob);
优点:WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。可以双向通信
缺点:需要前后端全都换上新的协议支持,WebSocket 技术也比较复杂, 成本比较高,后台开发工期大约需要一周
总结:
短轮询: 请求—响应 —-请求—响应 —-请求—响应
长轮询: 请求—保持挂起—有内容或超过时间才响应
长链接(SSE): 请求—连接—服务器端推送
websocket: 请求—连接—互相交互
最后:综合成本和时间简单项目用轮询,复杂的要求性能的用websocket