单纯记录一下之前项目做的一个webscoket链接方式。
应用场景是订单调到支付页面,之前是轮询查询用户是否支付成功,后来优化成webscoket链接。
由于应用的地方不多,所以用的原生webscoket。
首先得判断浏览器支不支持webscoket链接方式,不支持的话还是需要用轮询来兜底。
if ('WebSocket' in window) {
// 用webscoket
// 后面的代码全部放这里面就行
} else {
// 轮询
}
支持的话先实例化一个Webscoke实例(这是个vue项目,建议方法开始申明 const that = this ,不然里面的this指向问题很麻烦)
const socketUrl = `ws://接口地址?token=${token}` // 我是直接把参数拼到地址后面的
if (that.websocket != null) {
that.websocket.close()
that.websocket = null
}
that.websocket = new WebSocket(socketUrl)
成功打开的话会触发
that.websocket.onopen = function() {
that.scoketNum = 0 // 记录链接失败次数,失败三次后改为轮询
}
接受服务端消息
onmessage方法的触发时机是前端页面做了摸个操作,传给服务器,服务器就会推一条消息过来,进而触发onmessage,要是页面一直没有操作,就需要发一个心跳包给服务器来维持心跳(链接),因为webscoket默认只会维持60s 。
that.websocket.onmessage = function(msg) {
// 能接受消息,置为true可正常关闭,否则关闭的时候转轮询
that.webscoketFlag = true // 我这边传参错误不会触发error事件,也就不会三次链接失败后改为轮询,所以加一个标志位
// console.log('收到服务端消息', msg.data)
let code = JSON.parse(msg.data).code
}
// 发请求,拿到你需要的接口的数据---
payState(that.orderId).then((data) => {
if (data.code == 1) {
// 拿到想要的结果,停止发送心跳,关闭webscoket。
heartCheck.reset()
that.websocket.close()
that.websocket = null
that.timer && clearInterval(this.timer)
} else {
// 继续发心跳包
if (that.websocket.readyState === 1) {
heartCheck.reset().start() //拿到任何消息都说明当前连接是正常的
}
}
})
}
链接关闭事件
that.websocket.onclose = function() {
console.log('关闭了')
if (!that.webscoketFlag) {
// 走这里证明链接有问题,换轮询
that.timer = setInterval(() => {
// do something
}, 1000)
}
heartCheck.reset() // 停止心跳
that.websocket = null
}
链接错误
that.websocket.onerror = function() {
console.log('异常报错')
// let timeout = null
that.webscoketFlag = true
that.scoketNum++
// webscoket意外报错,重连五次,3次还未连接上,改为轮询
if (that.scoketNum < 3) {
setTimeout(() => {
that.init()
}, 100)
return
}
console.log('web报错,换轮询')
// 开启轮询
that.websocket.close()
that.websocket = null
that.scoketNum = 0
that.timer = setInterval(() => {
// do something
}, 1000)
}
心跳包设置
//websocket维持连接检测
var heartCheck = {
timeout: 50000, //50s发一次
timeoutObj: null,
serverTimeoutObj: null,
reset: function() {
clearTimeout(this.timeoutObj)
clearTimeout(this.serverTimeoutObj)
return this
},
start: function() {
var self = this
this.timeoutObj = setTimeout(function() {
console.log('发送心跳包')
//onmessage接受到消息说明连接正常
that.websocket &&
that.websocket.send( // 和后端约定好的字段
JSON.stringify({
code: 103,
msg: '客户端心跳包',
id: that.orderId[0],
})
)
self.serverTimeoutObj = setTimeout(function() {
console.log('超时未重置')
that.websocket.close()
}, self.timeout)
}, this.timeout)
},
}
一定要注意this指向问题,组件销毁的时候记得 this.timer && clearInterval(this.timer)
完整代码