需求:
需求实现监听服务端推送过来的消息,效果见下图:
用户某一个动作触发消息发送,在监听接口收到消息并展示出来。
解决方案:
ajax轮询(短轮询)
原理:客户端每隔几秒就发送一次请求,服务器接到请求后马上返回响应信息并关闭连接。
优点:程序编写比较容易。
缺点:请求次数多,请求中有大半是无用,浪费带宽和服务器资源。
long poll (长轮询)
原理:跟ajax轮询差不多,都是采用轮询的方式,区别在于:服务端收到请求后,检测数据是否有新数据,有则立即返回并关闭,无则挂起一直不返回Response直到超时关闭。关闭后客户端再次发起请求建立连接,周而复始。
优点:客户端的请求次数会大量减少
缺点:服务端请求挂起同样会导致资源的浪费
小结:
1.HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP连接就结束了。
2.Ajax轮询与long poll都属于不断发送http请求,然后等待服务器处理,可以看到http协议一个特点,被动性!
webSocket
webSocket是html5一种新的协议,实现了浏览器与服务器之间的全双工通信,能很好的节省服务器资源与带宽,并在服务器端与浏览器端实现实时通行,他建立在TCP之上, 同http一样,通过tcp来传输数据。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
webSocket客户端实例
使用如下的代码可以实现上面图片收到实时消息的效果。
//实时消息
startWebSocket(){
let this_=this;
let wsUrl=urlConfig.wsUrl+localStorage.getItem("access_token");//websocket接口地址
let ws = new WebSocket(wsUrl);
ws.onclose = function () {
this_.reConnect(wsUrl);//重新连接
console.log("连接已关闭 "+new Date());
};
ws.onerror = function () {
this_.reConnect(wsUrl);//重新连接
console.log("连接异常 "+new Date());
};
ws.onopen = function () {
heartCheck.reset().start();//开始心跳检测
console.log("连接成功 "+new Date());
};
ws.onmessage = function (e) {
heartCheck.reset().start();//开始心跳检测
let data = JSON.parse(e.data);
this_.onMessageNotice(data);//获取到数据的回调
};
/*心跳检测:
1.如果当前连接着(onopen或onMessage),就开始心跳检测,即设置定时器一段时间后发送一条数据,发送后再过一段时间关闭连接;
如果在关闭之前,后端正常返回数据(会触发onMessage),会重置心跳检测就一直不会关闭连接。
2.如果当前异常或关闭(onclose,onerror),就重新建立连接;
*/
let heartCheck = {
timeout: 180000, //3分钟发一次心跳
timeoutObj: null,//定时器:延时发送一次心跳
serverTimeoutObj: null,//定时器:延时检测后端是否返回数据,如返回则还连着,如未返回则后端断了
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function(){
let this_ = this;
this.timeoutObj = setTimeout(function(){
ws.send("peng");
console.log("peng");
this_.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, this_.timeout)
}, this.timeout)
}
};
}
//重新连接websocket
reConnect(url) {
let this_=this;
if(this.lockReconnect) return;
this.setState({
lockReconnect:true//上锁
});
setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
this_.startWebSocket(url);
this_.setState({
lockReconnect:false//开锁
});
}, 5000);
}
//收到消息的回调
onMessageNotice(data){
notification.info({//antd 中的组件
message: "这是一条消息",
description: "消息描述",
});
//收到消息重新获取消息列表
this.getNewsList();
//播放声音
this.refs.audio.play();
}