- WebSocket简介?
- WebSocket是一个网络协议,跟HTTP协议基本没有关系,为了兼容现有浏览器的握手规范,借用了HTTP的协议来完成握手。HTTP协议只能由客户端发送请求,服务器不能主动联系客户端,然而WebSocket可以使客户端和服务器均可主动发送请求。
- WebSocket对象提供了一组API,用于创建和管理WebSocket连接,以及通过连接接收和发送数据。
- WebSocket建立连接的过程?
当Web应用程序调用new WebSocket(url)接口时,Browser就开始了与地址为url的WebServer建立握手连接的过程。
- Brower与WebSocket服务器通过TCP握手建立连接,如果这个建立连接失败,那么后面的过程就不会执行,Web应用程序将收到错误信息通知。
- 在TCP建立连接成功后,Browser通过http协议传送WebSocket支持的版本号,原始地址,主机地址等等一系列字段给服务器端。
- WebSocket服务器收到Browser发送来的请求后,如果数据包数据和格式正确,客户端和服务器端的协议版本号匹配等,就接受本次握手连接,并给出相应的数据回复,同样回复的数据包也是采用http协议传输。
- Browser收到服务器回复的数据后,如果数据内容等没有问题,就表示连接成功,触发onopen消息,此时Web开发者就可以在此时通过send接口向服务器发送数据。否则,握手连接失败,Web应用程序会收到onerror消息,并且能知道连接失败的原因。
3.报文(与http对比差异)
request请求:
response回应:
字段说明:
4.使用 (测试url: ws://121.40.165.18:8800)
1.创建WebSocket
let socket = new WebSocket(url)
2.WebSocket方法
socket.send() //send(data)使用连接传输数据
socket.close() //主动关闭WebSocket连接
3.WebSocket事件
socket.onopen //建立socket连接成功触发
socket.onmessage //建立socket连接成功返回的数据
socket.onerror //连接发生错误的时候触发
socket.onclose //连接关闭的时候触发
5.心跳:ws连接成功后,开始每几秒给服务器发送数据,发送的数据,然后通过服务器返回回来,来确定链接正常运行,如果发送过去,数据一直没有返回,假如超过1min
6.异常断开重连
1.错误状态码
1000:正常关闭 表示WebSocket连接正常关闭,没有错误发生。
1001:终端离开 表示终端用户离开或导航到其他页面。
1002:协议错误 表示由于协议错误,服务器无法理解客户端的请求。
1003:数据类型错误 表示由于接收到不符合预期数据类型的数据,服务器关闭了连接。
1005:无状态码 表示关闭帧没有包含任何状态码。这通常是由于连接丢失或意外关闭而导致的。
1006:连接中断 表示连接意外中断,可能是由于网络问题或服务器崩溃等原因。
1011:服务端禁止访问 表示服务器拒绝了客户端的连接请求。
2.非主动断开重连
当evt.code !== 1000时候在设置定时器重连
7.结合5和6的整个WebSocket实现代码如下
<template>
<div>
<div v-html="message"></div>
<button @click="ws.close()">快~点我</button>
</div>
</template>
<script>
import { baseUrl } from '../config/config' //外面引入let baseUrl = ws://121.40.165.18:8800导出
export default {
data(){
return {
ws: null,
message: '',
timer: null,
timerServe: null,
timerRe: null
}
},
mounted() {
this.initWebSocket(baseUrl)
},
methods: {
//初始化WebSocket
initConnectWebSocket(url){
let vm = this
vm.ws = new WebSocket(url)
vm.ws.onopen = () => {
vm.onOpen()
}
vm.ws.onmessage = (evt) => {
vm.onMessage(evt)
}
vm.ws.onclose = (evt) => {
vm.onClose(evt)
}
vm.ws.onerror = (evt) => {
vm.onError(evt)
}
},
//连接成功调用
onOpen(){
console.log('连接成功...');
this.startHeart()
},
//处理数据
onMessage(evt) {
this.resetHeart()
console.log(evt.data);
this.message = evt.data
},
//连接关闭触发
onClose(evt){
console.log('状态码:', evt.code, '原因:', evt.reason);
if (evt.code !== 1000) {
this.reconnect()
} else {
this.timer && clearTimeout(this.timer)
this.timerServe && clearTimeout(this.timerServe)
}
},
//连接错误触发
onError(evt) {
console.log('错误信息:',evt);
},
//开启心跳
startHeart() {
this.timerRe && clearTimeout(this.timerRe)
this.timer = setTimeout(() => {
this.ws.send('hello')
this.timerServe = setTimeout(() => {
this.reconnect()
}, 4 * 1000)
}, 2 * 1000)
},
//重置心跳
resetHeart() {
this.timer && clearTimeout(this.timer)
this.timerServe && clearTimeout(this.timerServe)
this.startHeart()
},
//重新连接
reconnect() {
this.timerRe && clearTimeout(this.timerRe)
this.timerRe = setTimeout(() => {
this.initWebSocket(baseUrl)
}, 1000)
}
},
//组件销毁
beforeDestroy() {
if(this.ws) {
this.ws.close()
this.ws = null
}
if(this.timer) {
clearTimeout(this.timer)
this.timer = null
}
if(this.timerServe) {
clearTimeout(this.timerServe)
this.timerServe = null
}
if(this.timerRe) {
clearTimeout(this.timerRe)
this.timerRe = null
}
}
}
</script>