#为什么要使用websocket
在浏览器与服务器通信之间,传统的http请求在某些场景下并不理想,比如实时聊天,实时性的小游戏等等,
其中面临主要的两个缺点:
-
无法做到消息的实时性
-
服务器无法主动推送信息
其基于http的主要解决方案有:
-
基于ajax的轮询:客户端定时或者动态相隔短时间内不断向服务器请求接口,询问服务器是否有新信息;其缺点也很明显;多余的空请求(浪费资源)、数据获取有延时;
-
Long poll(长轮询):其中采用的是阻塞性的方案,客户端向服务器发起ajax请求,服务器挂起该请求不返回数据直接有新的数据,客户端接收到数据之后再次执行long poll;该方案中每个请求都挂起了服务器,在大量连接的场景下是不可以接收的
可以看到,基于 HTTP 协议的方案都包含一个本质缺陷 —— 「被动性」,服务端无法下推消息,仅能由客户端发起请求不断询问是否有新的消息,同时对于客户端与服务端都存在性能消耗。
WebSocket 是 HTML5 开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。 WebSocket 通信协议于2011年被IETF定为标准RFC 6455,WebSocketAPI 被 W3C 定为标准。 在 WebSocket API 中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
WebSocket 是 HTML5 中提出的新的网络协议标准,其包含几个特点:
-
建立于 TCP 协议之上的应用层;
-
一旦建立连接(直到断开或者出错),服务端与客户端握手后则一直保持连接状态,是持久化连接;
-
服务端可通过实时通道主动下发消息;
-
数据接收的「实时性(相对)」与「时序性」;
-
较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
-
支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
# 为什么要使用心跳机制呢
遇到的问题:
实时聊天过程中,
- websocket连接后,长时间远端和客户端不发消息,服务端会把websocket给断开;
- 所以就需要一种机制来检测客户端和服务端是否处于正常的链接状态。
- 因此就有了websocket的‘心跳监测’。
- 还有心跳,说明还活着,没有心跳说明已经断开了。
关于websocket的心跳重连机制
- 心跳机制是每隔一段时间会向服务器发送一个数据包:
告诉服务器(后台)自己还活着,同时客户端(浏览器)会 确认服务器端是否还活着
- 如果还活着的话,就会回传一个数据包给客户端
- 服务端断开连接了。客户端需要重连~
webscoket导致的兼容问题 可以用短轮询和长轮询代替,对浏览器的版本兼容性考虑
判断浏览器的版本,可以使用navigator对象的userAgent属性来获取浏览器的信息。userAgent属性返回一个字符串,其中包含了浏览器的版本信息。
那么如何进行判断呢
以下就是个案例
let browser = ""; // 存储浏览器名称
// 判断浏览器类型
if (userAgent.indexOf("msie") > -1 || userAgent.indexOf("trident") > -1) {
browser = "IE";
} else if (userAgent.indexOf("firefox") > -1) {
browser = "Firefox";
} else if (userAgent.indexOf("chrome") > -1 && userAgent.indexOf("edge") === -1) {
browser = "Chrome";
} else if (userAgent.indexOf("safari") > -1 && userAgent.indexOf("chrome") === -1) {
browser = "Safari";
} else if (userAgent.indexOf("edge") > -1) {
browser = "Edge";
}
// 判断浏览器版本
let version;
switch (browser) {
case "IE":
version = userAgent.match(/(?:msie|rv:)\s?([\d.]+)/)[1]; // 匹配IE浏览器的版本
break;
case "Firefox":
version = userAgent.match(/firefox\/([\d.]+)/)[1]; // 匹配Firefox浏览器的版本
break;
case "Chrome":
version = userAgent.match(/chrome\/([\d.]+)/)[1]; // 匹配Chrome浏览器的版本
break;
case "Safari":
version = userAgent.match(/version\/([\d.]+)/)[1]; // 匹配Safari浏览器的版本
break;
case "Edge":
version = userAgent.match(/edge\/([\d.]+)/)[1]; // 匹配Edge浏览器的版本
break;
}
// 进行兼容性判断
if (browser === "IE" && version < 10) {
// IE浏览器版本低于10
alert("您当前使用的浏览器版本过低,请升级!");
} else {
// 执行其他操作
console.log(`当前浏览器为${browser},版本号为${version}`);
}
短轮询
短轮询是通过HTTP请求来获取服务器数据,通常是固定的时间间隔发送请求,比如每隔5秒发送一次请求获取最新数据。在Vue3中,我们可以通过使用axios库来实现短轮询,代码如下:
export default {
data() {
return {
data: []
}
},
mounted() {
this.interval = setInterval(() => {
axios.get('/api/getData').then(res => {
this.data = res.data
})
}, 5000)
},
beforeUnmount() {
clearInterval(this.interval)
}
}
长轮询
长轮询是通过HTTP请求来获取服务器数据,但该请求会一直保持连接状态,直到服务器端有数据更新或者超时才会返回数据。在Vue3中,我们可以通过使用axios库实现长轮询,代码如下:文章来源:https://www.toymoban.com/news/detail-762932.html
export default {
data() {
return {
data: []
}
},
async mounted() {
while (true) {
try {
const res = await axios.get('/api/getData', {
timeout: 60000 // 设置超时时间
})
this.data = res.data
} catch (err) {
console.error(err)
}
}
}
}
这里通过使用while循环来保持连接状态,使用axios库发送get请求获取最新数据。在请求失败或超时后进行异常处理,可以避免程序崩溃。需要注意的是,长轮询需要设置超时时间,否则可能会导致资源耗尽。文章来源地址https://www.toymoban.com/news/detail-762932.html
到了这里,关于websocket以及心跳机制的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!