压力的产生源于你的行动跟不上你的期待
本周来谈谈前端websocet,
Websocket
- 构造函数Websocket()
- 参数
- 属性
- WebSocket.binaryType 使用二进制的数据类型连接。
- WebSocket.bufferedAmount (只读) 未发送至服务器的字节数。
- WebSocket.extensions (只读) 服务器选择的扩展。
- WebSocket.onclose 用于指定连接关闭后的回调函数
- WebSocket.onerror 用于指定连接失败后的回调函数。
- WebSocket.onmessage 用于指定当从服务器接受到信息时的回调函数。
- WebSocket.onopen 用于指定连接成功后的回调函数。
- WebSocket.protocol (只读) 服务器选择的下属协议。
- WebSocket.readyState (只读) 当前的链接状态。
- WebSocket.url (只读) WebSocket 的绝对路径。
- 方法
- 事件
- 直接上实战代码
构造函数Websocket()
var aWebSocket = new WebSocket(url [, protocols]);
返回一个websocket对象
参数
url
要连接的 URL;这应该是 WebSocket 服务器将响应的 URL。
一般为ws:而不是http[s]协议
protocols
一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议,这样单个服务器可以实现多个 WebSocket 子协议(例如,你可能希望一台服务器能够根据指定的协议(protocol)处理不同类型的交互)。如果不指定协议字符串,则假定为空字符串。
属性
WebSocket.binaryType 使用二进制的数据类型连接。
返回值一条DOMString:
“blob” 如果传输的是 Blob 类型的数据。 “arraybuffer” 如果传输的是 ArrayBuffer 类型的数据。
WebSocket.bufferedAmount (只读) 未发送至服务器的字节数。
WebSocket.bufferedAmount是一个只读属性,
用于返回已经被send()方法放入队列中但还没有被发送到网络中的数据的字节数。 一旦队列中的所有数据被发送至网络,则该属性值将被重置为 0。
但是,若在发送过程中连接被关闭,则属性值不会重置为 0。如果你不断地调用send(),则该属性值会持续增长
WebSocket.extensions (只读) 服务器选择的扩展。
是只读属性,返回服务器已选择的扩展值。目前,链接可以协定的扩展值只有空字符串或者一个扩展列表。
WebSocket.onclose 用于指定连接关闭后的回调函数
WebSocket.onclose 属性返回一个事件监听器, 这个事件监听器将在 WebSocket 连接的readyState 变为
CLOSED时被调用, 它接收一个名字为“close”的 CloseEvent 事件。
WebSocket.onerror 用于指定连接失败后的回调函数。
不可取消
当websocket的连接由于一些错误事件的发生 (例如无法发送一些数据) 而被关闭时,一个error事件将被引发。
WebSocket.onmessage 用于指定当从服务器接受到信息时的回调函数。
不可取消
message 事件会在 WebSocket 接收到新消息时被触发。
WebSocket.onopen 用于指定连接成功后的回调函数。
定义一个事件处理程序, 当WebSocket 的连接状态readyState 变为1时调用;这意味着当前连接已经准备好发送和接受数据。
这个事件处理程序通过 事件(建立连接时)触发。
WebSocket.protocol (只读) 服务器选择的下属协议。
WebSocket.protocol 是个只读属性,用于返回服务器端选中的子协议的名字; 这是一个在创建 WebSocket
对象时,在参数 protocols 中指定的字符串,当没有已建立的链接时为空串。
WebSocket.readyState (只读) 当前的链接状态。
返回当前 WebSocket 的链接状态,只读。
值
-
0
(WebSocket.CONNECTING) 正在链接中 -
1
(WebSocket.OPEN) 已经链接并且可以通讯 -
2
(WebSocket.CLOSING)连接正在关闭 -
3
(WebSocket.CLOSED) 连接已关闭或者没有链接成功
WebSocket.url (只读) WebSocket 的绝对路径。
是一个只读属性,返回值为当构造函数创建WebSocket实例对象时 URL 的绝对路径。
方法
WebSocket.close([code[, reason]])
WebSocket.close() 方法关闭 WebSocket 连接或连接尝试(如果有的话)。
如果连接已经关闭,则此方法不执行任何操作。
参数
code
可选
一个数字状态码,它解释了连接关闭的原因。如果没有传这个参数,默认使用 1005。CloseEvent的允许的状态码见状态码列表 。
reason
可选
一个人类可读的字符串,它解释了连接关闭的原因。这个 UTF-8 编码的字符串不能超过 123 个字节。
抛出的异常
INVALID_ACCESS_ERR
一个无效的code
SYNTAX_ERR
reason 字符串太长(超过 123 字节
)
WebSocket.send(data)
对要传输的数据进行排队。
data
用于传输至服务器的数据。它必须是以下类型之一:
-
USVString
文本字符串。字符串将以 UTF-8 格式添加到缓冲区,并且 bufferedAmount 将加上该字符串以 UTF-8 格式编码时的字节数的值。 -
ArrayBuffer
你可以使用一有类型的数组对象发送底层二进制数据;其二进制数据内存将被缓存于缓冲区,bufferedAmount 将加上所需字节数的值。 -
Blob
Blob 类型将队列 blob 中的原始数据以二进制中传输。 bufferedAmount 将加上原始数据的字节数的值。 -
ArrayBufferView
你可以以二进制帧的形式发送任何 JavaScript 类数组对象 ;其二进制数据内容将被队列于缓冲区中
。值 bufferedAmount 将加上必要字节数的值。
异常
INVALID_STATE_ERR
当前连接未处于 OPEN 状态。
SYNTAX_ERR
数据是一个包含未配对代理 (unpaired surrogates) 的字符串。
事件
使用 addEventListener() 或将一个事件监听器赋值给本接口的 oneventname
属性,来监听下面的事件。
-
close
当一个 WebSocket 连接被关闭时触发。 也可以通过onclose
属性来设置。 -
error
当一个 WebSocket 连接因错误而关闭时触发,例如无法发送数据时。 也可以通过onerror
属性来设置。 -
message
当通过 WebSocket 收到数据时触发。 也可以通过onmessage
属性来设置。 -
open
当一个 WebSocket 连接成功时触发。 也可以通过onopen
属性来设置。
直接上实战代码
后端处理
前端js代码
axios.get("/admin/gettoken").then((res) => {
adminumber = res.data.username;
token = res.data.token;
ws = new WebSocket(`ws://150.158.34.233:8080/websocket`[, token]);
//Wsbsocket(url[,protocols])第二个参数可选,可实现单个服务器可以实现多个 WebSocket 子协议
//我这里传递的是token
ws.onopen = function () {
console.log("连接成功");
};
ws.onmessage = function (event) {
console.log(event.data);//data为json格式,用json.parse()可以解析为对象形式
};
ws.onerror = function (evt) {
console.log("连接失败了");
};
ws.onclose = function (e) {
console.log("websocket 断开");
console.log("code:"+e.code+" "+"reason:"+e.reason+" "+"wasClean:" +e.wasClean);
};
});
发送消息
//发送实时信息
function sendmsg (id,toid,msg) {
let json = { fromUserName: id,toUserName:toid msg: msg, type: "person",chatid:1 };
ws.send(JSON.stringify(json));
};
以上代码是基本的接受和发送功能
但是
如果长时间无法跟服务器互动,可能会断开连接
心跳函数
可以写一个心跳函数,不断与服务器发送某个简洁的特殊字段保持连接
代码参照于WebSocket 经常断开原因,解决办法:心跳机制防止自动断开连接
var lockReconnect = false; //避免ws重复连接
var ws = null; // 判断当前浏览器是否支持WebSocket
var wsUrl = serverConfig.socketUrl;
createWebSocket(wsUrl); //连接ws
function createWebSocket(url) {
try{
if('WebSocket' in window){
ws = new WebSocket(url);
}
initEventHandle();
}catch(e){
reconnect(url);
console.log(e);
}
}
function initEventHandle() {
ws.onclose = function () {
reconnect(wsUrl);
console.log("llws连接关闭!"+new Date().toLocaleString());
};
ws.onerror = function () {
reconnect(wsUrl);
console.log("llws连接错误!");
};
ws.onopen = function () {
heartCheck.reset().start(); //心跳检测重置
console.log("llws连接成功!"+new Date().toLocaleString());
};
ws.onmessage = function (event) { //如果获取到消息,心跳检测重置
heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的
console.log("llws收到消息啦:" +event.data);
if(event.data!='pong'){
let data = JSON.parse(event.data);
}
};
}
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
ws.close();
}
function reconnect(url) {
if(lockReconnect) return;
lockReconnect = true;
setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
createWebSocket(url);
lockReconnect = false;
}, 2000);
}
//心跳检测
var heartCheck = {
timeout: 1000, //1分钟发一次心跳
timeoutObj: null,
serverTimeoutObj: null,
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function(){
var self = this;
this.timeoutObj = setTimeout(function(){
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
ws.send("ping");
console.log("ping!")
self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, self.timeout)
}, this.timeout)
}
}
对于同源协议中跳网页保持websocket连接不断开
目前没什么好的解决方案,大部分任的解决方案是进行SPA单页面,或是直接写个插件