WebSocket 是一种网络通讯协议,不少高级功能都须要它。初次接触 WebSocket 的人,都会问一样的问题:咱们已经有了 HTTP 协议,为何还须要另外一个协议?它能带来什么好处? 答案很简单,由于 HTTP 协议有一个缺陷:通讯只能由客户端发起。 举例来讲,咱们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议作不到服务器主动向客户端推送信息。 这种单向请求的特色,注定了若是服务器有连续的状态变化,客户端要获知就很是麻烦。咱们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低,很是浪费资源(由于必须不停链接,或者 HTTP 链接始终打开)。所以,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。javascript
它的最大特色就是,服务器能够主动向客户端推送信息,客户端也能够主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。前端
其余特色包括:java
(1)创建在 TCP 协议之上,服务器端的实现比较容易。web
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,而且握手阶段采用 HTTP 协议,所以握手时不容易屏蔽,能经过各类 HTTP 代理服务器。后端
(3)数据格式比较轻量,性能开销小,通讯高效。浏览器
(4)能够发送文本,也能够发送二进制数据。服务器
(5)没有同源限制,客户端能够与任意服务器通讯。websocket
(6)协议标识符是ws
(若是加密,则为wss
),服务器网址就是 URL。网络
var ws = new WebSocket("ws://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
}
复制代码
webSocket构造函数socket
let ws = new WebSocket('ws://localhost:8080');
复制代码
执行上面语句以后,客户端就会与服务器进行链接。
webSocket的状态(readyState)
readyState属性返回实例对象的当前状态,总共有四种状态。
CONNECTING:值为0, 正在链接
OPEN:值为1,链接成功
CLOSING:值为2,链接正在关闭
CLOSED:值为3,链接已经关闭
复制代码
websocket.onopen(链接成功以后的回调函数)
实例对象的onopen
属性,用于指定链接成功后的回调函数。
ws.onopen = function () {
ws.send('Hello Server!');
}
复制代码
若是要指定多个回调函数,可使用addEventListener
方法。
ws.addEventListener('open', function (event) {
ws.send('Hello Server!');
});
复制代码
websocket.onclose(关闭以后调用的方法)
实例对象的onclose
属性,用于指定链接关闭后的回调函数。
ws.onclose = function(event) {
console.log('onclose')
}
复制代码
若是要指定多个回调函数,可使用addEventListener
方法。
ws.addEventListener("close", function(event) {
console.log('onclose')
});
复制代码
websocket.onmessage(接受到服务器数据以后的回调函数)
ws.onmessage = function(event) {
// 获取数据event.data
var data = event.data;
// 处理数据
};
复制代码
websocket.send(向服务器端发送数据)
ws.send('your message')
复制代码
websocket.onerror(报错时调用的方法)
ws.onerror = function(event) {
// handle error event
};
复制代码
websocket是先后端交互的长链接,先后端也均可能由于一些状况致使链接失效而且相互之间没有反馈提醒。所以为了保证链接的可持续性和稳定性,websocket心跳重连就应运而生。在使用原生websocket的时候,若是设备网络断开,不会马上触发websocket的任何事件,前端也就没法得知当前链接是否已经断开。这个时候若是调用websocket.send方法,浏览器才会发现连接断开了,便会马上或者必定短期后(不一样浏览器或者浏览器版本可能表现不一样)触发onclose函数。后端websocket服务也可能出现异常,形成链接断开,这时前端也并无收到断开通知,所以须要前端定时发送心跳消息ping,后端收到ping类型的消息,立马返回pong消息,告知前端链接正常。若是必定时间没收到pong消息,就说明链接不正常,前端便会执行重连。为了解决以上两个问题,之前端做为主动方,定时发送ping消息,用于检测网络和先后端链接问题。一旦发现异常,前端持续执行重连逻辑,直到重连成功。
通常的心跳检测的函数:
// 心跳检测, 每隔一段时间检测链接状态,若是处于链接中,就向server端主动发送消息,来重置server端与客户端的最大链接时间,若是已经断开了,发起重连。
let heartCheck = {
// 心跳,比server端设置的链接时间稍微小一点,在接近断开的状况下以通讯的方式去重置链接时间。
timeout: 100000,
serverTimeoutObj: null,
reset: function() {
clearTimeout(this.serverTimeoutObj)
return this
},
start: function() {
this.serverTimeoutObj = window.setInterval(() => {
if (websocket.readyState === 1) {
websocket.send('ping')
} else {
window.clearTimeout(this.serverTimeoutObj)
// 处理逻辑:重连或者其余
}
}, this.timeout)
}
}
复制代码
function newWebSocket(option) {
console.log('new webSocket.....')
let websocket = null
// 判断当前环境是否支持websocket
if (window.WebSocket) {
if (!websocket) {
websocket = new WebSocket('你的请求地址')
}
} else {
console.log('not support websocket')
}
// 链接成功创建的回调方法
websocket.onopen = function(e) {
// 成功创建链接后,重置心跳检测
heartCheck.reset().start()
console.log('connected successfully')
}
// 链接发生错误,链接错误时会继续尝试发起链接
websocket.onerror = function() {
console.log(`onerror`)
newWebSocket()
}
// 接受到消息的回调方法
websocket.onmessage = function(e) {
console.log('onmessage', e.data)
var message = e.data
if (message) {
// 执行接收到消息的操做
if (option != undefined) {
// 执行传入对象的方法,传出消息
option.onmessage(message)
}
}
}
// 接受到服务端关闭链接时的回调方法
websocket.onclose = function() {
console.log('onclose')
}
// 监听窗口事件,当窗口关闭时,主动断开websocket链接,防止链接没断开就关闭窗口,server端报错
window.onbeforeunload = () => {
return websocket.close()
}
// 心跳检测, 每隔一段时间检测链接状态,若是处于链接中,就向server端主动发送消息,来重置server端与客户端的最大链接时间,若是已经断开了,发起重连。
var heartCheck = {
// 心跳,比server端设置的链接时间稍微小一点,在接近断开的状况下以通讯的方式去重置链接时间。
timeout: 100000,
serverTimeoutObj: null,
reset: function() {
clearTimeout(this.serverTimeoutObj)
return this
},
start: function() {
this.serverTimeoutObj = window.setInterval(() => {
if (websocket.readyState === 1) {
websocket.send('ping')
} else {
console.log('websocket stop', websocket.readyState)
window.clearTimeout(this.serverTimeoutObj)
newWebSocket(option)
}
}, this.timeout)
}
}
return websocket
}
复制代码