WebSocket
1. WebSocket 理解
1.1 WebSocket出现的原因
我们已经有了 HTTP 协议,为什么还需要另一个协议?
因为 HTTP 协议有一个缺陷:通信只能由客户端发起。
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。因此我们只能使用"轮询", 也就是每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。
<body>
<script>
//http是单向的,要东西才会给
setInterval(() => {
$.ajax({ //每隔10s向后台请求数据,这就是轮询
...
})
}, 10000)
</script>
</body>
然而轮询的效率比较低, 非常 浪费资源。轮询的缺陷--后台数据没变,间隔响应时间还会请求数据
因此为了更好地处理这种问题.WebSocket就 这样被发明了
1.2 WebSocket 简介
WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
特点 :
-
建立在 TCP 协议之上,服务器端的实现比较容易。
-
与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器
-
数据格式比较轻量,性能开销小,通信高效。
-
可以发送文本,也可以发送二进制数据。
-
没有同源(跨域)限制,客户端可以与任意服务器通信。
-
协议标识符是
ws
(如果加密,则为wss
),服务器网址就是 URL。
ws://example.com:80/some/path
2. 客户端API
2.1 WebSocket 构造函数
WebSocket
对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。
对于我们来时通过WebSocket
构造函数实例化WebSocket
对象, 在实例化过程中连接服务器
语法;
var aWebSocket = new WebSocket(url);
参数:
- url: 要连接的URL;这应该是WebSocket服务器将响应的URL
例子:
let ws = new WebSocket('ws://www.localhost:8080')在关闭
4. CLOSED: 值为3, 表示连
2.2 webSocket.readyState
实例的readyState
属性返回实例对象的当前状态, 共有四种状态
- CONNECTING: 值为0, 表示正在连接
- OPEN: 值为1, 表示连接成功, 可以通信了
- CLOSING: 值为2, 表示连接正接已经关闭, 或者 打开连接失败
switch (ws.readyState) {
case WebSocket.CONNECTING:
break;
case WebSocket.OPEN:
break;
case WebSocket.CLOSING:
break;
case WebSocket.CLOSED:
break;
default:
break;
}
3 webSocket.onopen
实例对象的onopen
方法, 用于执行连接成功后的回调函数
// socket 连接成功后触发事件
ws.onopen = function(){
// 像后端发送数据
ws.send("Hello Word")
}
如果需要指定多个回调函数, 可以使用addEventListener
事件绑定
ws.addEventListener('open', function (ev) {
ws.send('Hello Server!');
});
ws.addEventListener('open', function (ev) {
ws.send('你好');
});
2.4 webSocket.send()
实例对象的send()
方法用于向服务器发送数据。
发送文本数据
ws.send('hello word');
发送JSON数据
ws.send(JSON.stringify({name:'张三'}));
2.5 webSocket.onmessage
实例对象的onmessage
属性,用于指定收到服务器数据后的回调函数。
ws.onmessage = function(ev) {
var data = ev.data;
// 处理数据
};
ws.addEventListener("message", function(ev) {
var data = ev.data;
// 处理数据
});
2.6 webSocket.onclose
实例对象的onclose
属性, 指定连接关闭后的回调函数
注意: socket连接失败也会触发onclose
事件
ws.onclose = function(ev) {
console.log('关闭socket连接', ev)
};
ws.addEventListener("close", function(event) {
console.log('关闭socket连接', ev)
});
2.7 webSocket.onerror
实例对象的onerror
属性,用于指定报错时的回调函数。
socket.onerror = function(ev) {
// 处理错误
};
socket.addEventListener("error", function(ev) {
// 处理错误
});
3. WebSocket 封装
class JsSocket {
/**
* 构造方法, 进行初始化
* @param {String} url socket 连接地址
* */
constructor(url) {
this.url = url;
this.lockReconnect = false;
this.reconnectCount = 0
}
/**
* 开始连接
* @params { Function } callback
* */
connect(callback) {
this.callback = callback;
this.disconnect()
try {
console.log("JsSocket开始连接...", this.url)
this.ws = new WebSocket(this.url)
this.ws.onopen = function(ev) {
console.log("JsSocket onpen...", ev)
this.reconnectTimes = 0
}
this.ws.onmessage = function(ev) {
console.log("JsSocket onmessage...", ev)
let data = ev.data;
if (!data) {
data = JSON.parse(data)
}
callback(data)
}
this.ws.onclose = (ev) => {
console.log("JsSocket onclose...", ev)
this.reconnect()
}
this.ws.onerror = (ev) => {
console.log("JsSocket onerror...", ev)
this.reconnect()
}
} catch (error) {
console.log("JsSocket", error)
}
}
/**
* 断开连接
* */
disconnect() {
if (this.ws) {
this.ws.onclose = null;
this.ws.close()
this.ws = null
}
}
/**
* 发送消息
* @params { Object } data 消息内容
* */
send(data) {
if (this.ws) {
this.ws.send(data)
}
}
/**
* 重新连接
* */
reconnect() {
if (this.lockReconnect || this.reconnectCount > 5) {
console.log('JsSocket 重连锁定 或者 超过重连次数')
return;
}
this.lockReconnect = true;
setTimeout(() => {
this.reconnectCount++;
console.log('JsSocket 重连...')
this.connect(this.callback)
this.lockReconnect = false
}, 3000)
}
}
网友评论