webSocket通信封装
一. js使用WebSocket介绍
二. webSocket js封装使用
三. js封装代码
一. js使用WebSocket介绍
1. 创建WebSocket实例
url:url之前需添加ws://(未加密)或wss://(已加密),类似http://、https://
protocol:与服务端定义的协议名称相同,协议的参数例如XMPP(Extensible Messaging and Presence Protocol)、SOAP(Simple Object Access Protocol)或者自定义协议
var ws = new WebSocket('ws://url');
var ws1 = new WebSocket('ws://url', 'myprotocol');
var ws2 = new WebSocket('ws://url', ['protocol_1','protovol_2']));
1
2
3
2.属性
①readyState属性:WebSocket当前连接状态
属性值 属性常量 描述
0 CONNECTING 正在与服务端建立WebSocket连接,还没有连接成功
1 OPEN 连接成功并打开,可以发送消息
2 CLOSING 进行关闭连接的操作,且尚未关闭
3 CLOSE 连接已关闭或不能打开
通过 ws.readyState属性查看当前连接状态
alert('ws连接状态:' + ws.readyState);
1
②bufferedAmount:检查传输数据的大小,当客户端传输大量数据时使用避免网络饱和
③protocol:在构造函数中使用,protocol参数让服务端知道客户端使用的WebSocket协议。而WebSocket对象的这个属性就是指的最终服务端确定下来的协议名称,可以为空
3. 方法
①发送数据:send()
②关闭连接:closed()
//发送数据
var message = {
id: 1,
title: '发送ws数据'
}
ws.send(JSON.stringify(message)); // 复杂的数据结构要先进行序列化
//关闭连接
ws.close()
4. 事件
WebSocket API是纯事件驱动,建立连接之后,可自动发送状态改变的数据和通知
事件值 描述
onopen 当建立websocket连接时触发,只触发一次
onerror 当连接出现错误时触发-因为当触发了onerror之后连接就会触发关闭事件
onmessage 当服务端发送数据时触发,可多次触发,页面数据展示处理模块–实现轮询
onclose 当websocket连接关闭时触发,只触发一次
使用示例
var ws = new WebSocket('ws://url');
// 获取连接状态
console.log('ws连接状态:' + ws.readyState);
//监听是否连接成功
ws.onopen = function () {
console.log('ws连接状态:' + ws.readyState);
//连接成功则发送一个数据
ws.send('test1');
}
// 接听服务器发回的信息并处理展示
ws.onmessage = function (data) {
console.log('接收到来自服务器的消息:');
console.log(data);
//完成通信后关闭WebSocket连接
ws.close();
}
// 监听连接关闭事件
ws.onclose = function () {
// 监听整个过程中websocket的状态
console.log('ws连接状态:' + ws.readyState);
}
// 监听并处理error事件
ws.onerror = function (error) {
console.log(error);
}
二. webSocket js封装使用
创建一个js文件, 代码在下, 最后将方法暴露出去, 使用的时候可以直接引用文件中的方法 调用, 或者 将该js文件挂载在vue的prototype中
直接引用文件 方法 调用
import {createWebSocket} from '@/utils/socket’
createWebSocket()
挂载在vue的prototype中
3. 整个项目只有一条webSocket通信:
① 在登录后即可创建webSocket通信, 接受的数据中可定义一个参数, 该参数来控制是 做什么功能
例如这里 :
“webSocket_device_transport” 是某一个界面需要实时添加的一些数据
“webSocket_device_alarm” 是一个全局提示弹框, 需要添加的数据
② 创建了 new Map(); key和value 用来一一对应发送和接受的数据
//思路
var globalCallback = new Map(); //创建 new Map()
globalCallback.set(key,callback); //发送数据的时候, 要定义一个唯一的key 和后端返回的key是一一对应, 定义一个回调函数用来接收数据后处理数据
//例如上图片中 接收的数据 res.method == "webSocket_device_transport", 用sn作为唯一的标识符,
// 客户端在发送数据时 globalCallback.set("sn",resultFunc), 通过globalCallback存了一个key为"sn"的回调函数,
// 然后通信接收的数据中 返回作为标识符的"sn", 用来查找存的回调函数, 然后处理数据. (因为处理数据的方法可能有多种, 不唯一, 所以用回调函数)
const callback = globalCallback.get(ret.sn)
callback(ret);
三. js封装代码
import { getToken} from '@/utils/auth'
var websock = null;
let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码
let isConnect = false; //连接标识 避免重复连接
let checkMsg = "heartbeat"; //心跳发送/返回的信息 服务器和客户端收到的信息内容如果如下 就识别为心跳信息 不要做业务处理
var globalCallback = new Map();
let createWebSocket = () => {
try {
initWebSocket(); //初始化websocket连接
} catch (e) {
console.log("尝试创建连接失败");
reConnect(); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接
}
};
//定义重连函数
let reConnect = () => {
console.log("尝试重新连接");
if (isConnect) return; //如果已经连上就不在重连了
rec && clearTimeout(rec);
rec = setTimeout(function () { // 延迟5秒重连 避免过多次过频繁请求重连
createWebSocket();
}, 5000);
};
//设置关闭连接
let closeWebSocket = () => {
websock.close();
};
//心跳设置
var heartCheck = {
timeout: 20000, //每段时间发送一次心跳包 这里设置为20s
timeoutObj: null, //延时发送消息对象(启动心跳新建这个对象,收到消息后重置对象)
start: function () {
this.timeoutObj = setInterval(function () {
console.log("hearting ....")
if (isConnect) websock.send(checkMsg);
}, this.timeout);
},
reset: function () {
clearInterval(this.timeoutObj)
this.start();
},
stop: function (){
clearInterval(this.timeoutObj)
}
};
// 初始化websocket
function initWebSocket() {
// ws地址
// const wsUri = "ws://10.27.100.151:5000/occpws/customWebSocket";
const wsUri = "wss://cloudiot.notioni.com/ws/occpws/customWebSocket";
websock = new WebSocket(wsUri,getToken())
websock.onmessage = function (e) {
websocketonmessage(e)
}
websock.onclose = function (e) {
websocketclose(e)
}
websock.onopen = function () {
websocketOpen()
heartCheck.start();
}
// 连接发生错误的回调方法
websock.onerror = function () {
console.log('WebSocket连接发生错误')
isConnect = false; //连接断开修改标识
reConnect(); //连接错误 需要重连
}
}
// 实际调用的方法
function sendSock(agentData, callback, key) {
if (!websock){
initWebSocket()
}
globalCallback.set(key,callback)
if (websock.readyState === websock.OPEN) {
// 若是ws开启状态
websocketsend(agentData)
} else if (websock.readyState === websock.CONNECTING) {
// 若是 正在开启状态,则等待1s后重新调用
setTimeout(function () {
sendSock(agentData, callback,key)
}, 2000)
} else {
// 若未开启 ,则等待1s后重新调用
setTimeout(function () {
sendSock(agentData, callback,key)
}, 2000)
}
}
function getSock(key,callback) {
globalCallback.set(key,callback)
}
// 数据接收
function websocketonmessage(e) {
let ret = JSON.parse(decodeUnicode(e.data))
if (!ret) {
heartCheck.reset()
} else {
if (ret.msg === "websocket connect success") {
} else {
if (ret.method === "webSocket_device_transport"){
const callback = globalCallback.get(ret.sn)
if (callback && typeof callback === "function")
callback(ret);
}else if(ret.method === "webSocket_device_alarm"){
const callback = globalCallback.get('deviceAlert')
if (callback && typeof callback === "function")
callback(ret);
}
}
}
// globalCallback(JSON.parse(e.data))
function decodeUnicode(str) {
str = str.replace(/\\/g, "%");
//转换中文
str = unescape(str);
//将其他受影响的转换回原来
str = str.replace(/%/g, "\\");
//对网址的链接进行处理
str = str.replace(/\\/g, "");
return str;
}
}
// 数据发送
function websocketsend(agentData) {
console.log("数据发送",JSON.stringify(agentData))
websock.send(JSON.stringify(agentData))
}
// 关闭
function websocketclose(e) {
console.log(e)
isConnect = false ; //断开后修改标识
heartCheck.stop()
console.log('connection closed (' + e.code + ')')
}
// 创建 websocket 连接
function websocketOpen(e) {
isConnect = true
console.log('连接成功')
}
//登录成功后再建立连接
//initWebSocket()
// 将方法暴露出去
export {
sendSock,
getSock,
createWebSocket,
closeWebSocket,
initWebSocket
}
————————————————
版权声明:本文为CSDN博主「Hello 阿凡达」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38746300/article/details/128675243
联系客服