内容简介:微信基础库1.7.0之后的版本提供了新版的WebSocket API,考虑到兼容性问题,尝试整合新旧两种版本的API,进行简单的封装。从以下几个角度对微信小程序中所提供的WebSocket API封装支持1.7.0+,连接后会返回一个SocketTask对象,在该对象上监听该连接的各种事件与执行发送消息等操作。
微信基础库1.7.0之后的版本提供了新版的WebSocket API,考虑到兼容性问题,尝试整合新旧两种版本的API,进行简单的封装。
从以下几个角度对微信小程序中所提供的WebSocket API封装
- API兼容性
- 重连机制
小程序WebSocket API
旧版WebSocket API的使用
- 创建 - wx.connectSocket
- 发送消息 - sendSocketMessage
- 监听事件 - onSocketOpen
let socketOpen = false
const socketMsgQueue = []
// 连接socket
wx.connectSocket({
url: 'test.php'
})
// 监听打开事件
wx.onSocketOpen(function(res) {
socketOpen = true
for (let i = 0; i < socketMsgQueue.length; i++){
sendSocketMessage(socketMsgQueue[i])
}
socketMsgQueue = []
})
// 发送消息
function sendSocketMessage(msg) {
if (socketOpen) {
wx.sendSocketMessage({
data:msg
})
} else {
socketMsgQueue.push(msg)
}
}
新版WebSocket API的使用
支持1.7.0+,连接后会返回一个SocketTask对象,在该对象上监听该连接的各种事件与执行发送消息等操作。
let socketTask = wx.connectSocket({
url: 'test.php'
})
// 监听打开事件
socketTask.onOpen(function(res) {
socketOpen = true
// 发送信息
socketTask.send({msg: "hello world"})
})
并发数
-
1.7.0及以上版本,最多可以同时存在5个WebSocket连接。 -
1.7.0以下版本,一个小程序同时只能有一个WebSocket连接,如果当前已存在一个 WebSocket 连接,会自动关闭该连接,并重新创建一个WebSocket连接。
模块封装
简单封装封装一个兼容新旧socketAPI的模块,仅考虑存在单个socket连接的情况
创建与事件监听
- 新版: 在socket连接时会返回一个socketTask对象,监听事件是在该对象的基础上进行
- 旧版: 直接使用wx放进行创建与监听方法
统一创建与添加监听函数
init() {
let st = this.connect()
this.listen(st)
this.manualClose = false
}
创建连接
connect() {
let st = wx.connectSocket(this.config.server)
return st
}
添加事件监听函数
listen(st) {
if (st !== undefined) {
this.ws = st
this.ws.onOpen(() => this.openHandle())
this.ws.onError(() => this.errorHandle())
this.ws.onClose(() => this.closeHandle())
this.ws.onMessage(res => this.messageHandle(res))
} else {
wx.onSocketOpen(() => this.openHandle())
wx.onSocketError(() => this.errorHandle())
wx.onSocketClose(() => this.closeHandle())
wx.onSocketMessage(res => this.messageHandle(res))
}
}
重连机制
预设标记位
retryLock = false; // 避免多次同时重连 socketOpen = false; // 连接状态 manualClose = false; // 主动断开标记
在连接关闭监听函数中执行重连
closeHandle() {
console.info('WebSocket closed')
this.socketOpen = false
this.retryLock = false
// 不论是error还是close都会触发close事件,统一在这里进行重连
// 初次连接失败不进行重连(失败不会进入到onOpen的监听事件中,那时未声明retryTimes变量)
this.retryTimes !== undefined && this.reconnect()
}
判断重连锁与是否主动断开进行重连
reconnect() {
if (this.retryLock) return
this.retryLock = true
// 若manualClose为true,表明不是主动断开
if (!this.manualClose) {
// 开始重连
setTimeout(() => {
this.retry()
}, this.retryInterval)
}
}
重连函数,包含重连次数的限制
retry() {
if (
this.socketOpen ||
(this.retryTimes > 0 && this.retryCount <= this.retryTimes)
) {
console.warn(`reconnect ending. reconnect ${this.retryTimes} times`)
if (!this.socketOpen) {
this.config.closeCallback()
}
return
}
this.retryTimes += 1
console.warn(`[ ${this.retryTimes} ]th reconnect WebSocket...`)
this.init()
}
消息队列
添加消息队列,当重连后自动发送缓存消息
openHandle() {
this.retryTimes = 0
this.socketOpen = true
this.retryLock = false
this.messageQueue.map(e => this.send(e))
this.messageQueue = []
}
若发送时断开则先将消息缓存到消息队列中
send(value) {
let data = this.msgWrapper(value)
data = JSON.stringify(data)
if (!this.socketOpen) {
this.messageQueue.push(data)
} else {
if (this.ws) {
this.ws.send({ data })
} else {
wx.sendSocketMessage({ data })
}
}
}
辅助函数
添加一些包裹消息格式的 工具 函数
messageIndex = 0;
helper = {
isPlainObject: val =>
Object.prototype.toString.call(val) === '[object Object]',
nextId: () => {
this.messageIndex += 1
return this.messageIndex
},
id: () => Date.now() + '.' + this.helper.nextId()
};
msgWrapper(data) {
let msg = data
if (this.helper.isPlainObject(msg)) {
if (msg.type) {
return msg
} else {
return this.msgWrapper({ type: 'message', msg, id: this.helper.id() })
}
} else {
return this.msgWrapper({ type: 'message', msg, id: this.helper.id() })
}
}
完整代码
export default class WXWebSocket {
messageQueue = []; // 消息队列
retryLock = false; // 避免多次同时重连
socketOpen = false;
manualClose = false; // 主动断开标记
constructor(config) {
this.config = config || {}
// 重连间隔
this.retryInterval =
this.config.retryInterval && this.config.retryInterval > 100
? this.config.retryInterval
: 3000
// 重连次数
this.retryCount = this.config.retryCount || 5
this.init()
}
init() {
let st = this.connect()
this.listen(st)
this.manualClose = false
}
connect() {
let st = wx.connectSocket(this.config.server)
console.log('current socket: ', st)
return st
}
listen(st) {
// 添加监听事件
if (st !== undefined) {
// 若存在SocketTask,则要通过readyState判断状态
// CONNECTING: 0
// OPEN: 1
// CLOSING: 2
// CLOSE: 3
this.ws = st
this.ws.onOpen(() => this.openHandle())
this.ws.onError(() => this.errorHandle())
this.ws.onClose(() => this.closeHandle())
this.ws.onMessage(res => this.messageHandle(res))
} else {
wx.onSocketOpen(() => this.openHandle())
wx.onSocketError(() => this.errorHandle())
wx.onSocketClose(() => this.closeHandle())
wx.onSocketMessage(res => this.messageHandle(res))
}
}
close() {
this.manualClose = true
if (this.ws) {
this.ws.close()
} else {
wx.closeSocket()
}
}
send(value) {
console.log('send value: ', value)
let data = this.msgWrapper(value)
data = JSON.stringify(data)
if (!this.socketOpen) {
// add new message to queue
this.messageQueue.push(data)
} else {
if (this.ws) {
this.ws.send({ data })
} else {
wx.sendSocketMessage({ data })
}
}
}
openHandle() {
console.info('WebSocket connected')
this.retryTimes = 0
this.socketOpen = true
this.retryLock = false
this.messageQueue.map(e => this.send(e))
this.messageQueue = []
}
errorHandle() {
console.error('WebSocket error')
this.socketOpen = false
}
closeHandle() {
console.info('WebSocket closed')
this.socketOpen = false
this.retryLock = false
// 不论是error还是close都会触发close事件,统一在这里进行重连
// 初次连接失败不进行重连(失败不会进入到onOpen的监听事件中,那时未声明retryTimes变量)
this.retryTimes !== undefined && this.reconnect()
}
reconnect() {
if (this.retryLock) return
this.retryLock = true
// 若manualClose为true,表明不是主动断开
if (!this.manualClose) {
// 开始重连
setTimeout(() => {
this.retry()
}, this.retryInterval)
}
}
retry() {
if (
this.socketOpen ||
(this.retryTimes > 0 && this.retryCount <= this.retryTimes)
) {
console.warn(`end reconnect. reconnect ${this.retryTimes} times`)
if (!this.socketOpen) {
this.config.closeCallback()
}
return
}
this.retryTimes += 1
console.warn(`[ ${this.retryTimes} ]th reconnect WebSocket...`)
this.init()
}
messageHandle(res) {
this.config.responseCallback(res)
}
msgWrapper(data) {
let msg = data
if (this.helper.isPlainObject(msg)) {
if (msg.type) {
return msg
} else {
return this.msgWrapper({ type: 'message', msg, id: this.helper.id() })
}
} else {
return this.msgWrapper({ type: 'message', msg, id: this.helper.id() })
}
}
messageIndex = 0;
helper = {
isPlainObject: val =>
Object.prototype.toString.call(val) === '[object Object]',
nextId: () => {
this.messageIndex += 1
return this.messageIndex
},
id: () => Date.now() + '.' + this.helper.nextId()
};
}
使用
创建连接
let socketTask = new WXWebSocket({
server: this.wsServerOption,
responseCallback: e => {
let { data } = e
let { msg } = JSON.parse(data)
this.msgStack.push(msg)
},
closeCallback: () => {
this.socketTask = null
}
})
this.socketTask = socketTask
发送消息
sendWSMessage(msg) {
this.msgStack.push(msg)
this.socketTask && this.socketTask.send(msg)
},
关闭连接
closeWS() {
if (!this.socketTask) return
if (this.socketTask.socketOpen) {
this.socketTask.close()
this.socketTask = null
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 小程序优化实践
- 小程序webview应用实践
- 编程日历小程序,对小程序云开发和生成海报的实践
- 给小程序再减重 30% 的秘密(京喜小程序首页瘦身实践)
- 程序员必备,“向上管理” 实践指南
- Clojure 并发实践:使用 pmap 加速程序
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Security Testing Cookbook
Paco Hope、Ben Walther / O'Reilly Media / 2008-10-24 / USD 39.99
Among the tests you perform on web applications, security testing is perhaps the most important, yet it's often the most neglected. The recipes in the Web Security Testing Cookbook demonstrate how dev......一起来看看 《Web Security Testing Cookbook》 这本书的介绍吧!