微信小程序创建WebSocket链接使用到了uni.connectSocket(OBJECT)
这里主要讲一下单页面监听(局部监听)和多页面监听(全局监听)
:小程序中必须是 wss://
协议
- 微信小程序平台1.7.0 及以上版本,最多可以同时存在5个WebSocket 连接。老版本只支持一个socket连接
先来了解一下小程序的生命周期(只显示了主要的)
一、局部监听
在util文件夹下建立websocket.js文件,util文件也是我自己在项目根目录建立的,主要存放使用的工具。
let isSocketClose=false; // 是否关闭socket
let reconnectCount=5; // 重连次数
let heartbeatInterval=""; // 心跳定时器
let socketTask = null; // websocket对象
let againTimer = null;//断线重连定时器
let url = null;
let onReFn = null;
let onSucFn = null;
let onErrFn = null;
/**
* sockeUrl:websocet的地址
* onReceive:消息监听的回调
* onErrorEvent:抛出错误的回调,且弹窗连接失败的提示框
* onErrorSucceed:抛出成功回调,主要用于隐藏连接失败的提示框
* */
const sokcet= (sockeUrl,onReceive,onErrorEvent,onErrorSucceed)=> {
url = sockeUrl;
onReFn= onReceive;
onErrFn= onErrorEvent;
onSucFn= onErrorSucceed;
isSocketClose=false;
//判断是否有websocet对象,有的话清空
if(socketTask){
socketTask.close();
socketTask = null;
clearInterval(heartbeatInterval);
}
//WebSocket的地址
// 【非常重要】必须确保你的服务器是成功的,如果是手机测试千万别使用ws://127.0.0.1:9099【特别容易犯的错误】
let url = sockeUrl
// 连接
socketTask = uni.connectSocket({
url: url,
success(data) {
console.log("websocket连接成功");
clearInterval(againTimer)//断线重连定时器
},
fail: (err) => {
console.log("报错",err);
}
});
// 连接打开
socketTask.onOpen((res)=>{
console.log('WebSocket打开');
clearInterval(againTimer)//断线重连定时器
onErrorSucceed({isShow:false}) // 用于提示框的隐藏
heartbeatInterval && clearInterval(heartbeatInterval);
// 发送一次心跳
heartbeatInterval = setInterval(() => {
socket()
}, 1000)
})
// 监听连接失败
socketTask.onError((err)=>{
console.log('WebSocket连接打开失败,请检查',err);
//停止发送心跳
clearInterval(heartbeatInterval)
//如果不是人为关闭的话,进行重连
if (!isSocketClose) {
reconnect(url,onErrorEvent)
}
})
// // 监听连接关闭 -
socketTask.onClose((e) => {
console.log('WebSocket连接关闭!');
clearInterval(heartbeatInterval)
if (!isSocketClose) {
reconnect(url,onErrorEvent)
}
})
// 监听收到信息
socketTask.onMessage((res) => {
uni.hideLoading()
// console.log(res,'res监听收到信息')
let serverData = res.data
//与后端规定好返回值分别代表什么,写业务逻辑
serverData && onReceive(serverData);
});
}
const reconnect = (url,onErrorEvent)=>{
console.log('进入断线重连',isSocketClose);
clearInterval(againTimer)//断线重连定时器
clearInterval(heartbeatInterval);
socketTask && socketTask.close(); // 确保已经关闭后再重新打开
socketTask = null;
onErrorEvent({isShow:true,messge:'扫描头服务正在连接...'})
// 连接 重新调用创建websocet方法
againTimer = setInterval(()=>{
sokcet(url,onReFn,onErrFn,onSucFn)
console.log('在重新连接中...');
},1000)
}
const sendMsg = (msg)=>{ //向后端发送命令
msg = JSON.stringify(msg)
try{
//通过 WebSocket 连接发送数据
socketTask.send({
data: msg
});
}catch(e){
if(isSocketClose){
return
}else{
reconnect(url,onErrFn)
}
}
}
// 关闭websocket【必须在实例销毁之前关闭,否则会是underfined错误】beforeDestroy() {websocetObj.stop();}
const stop = ()=>{
isSocketClose = true
clearInterval(heartbeatInterval);
clearInterval(againTimer)//断线重连定时器
socketTask.close(); // 确保已经关闭后再重新打开
socketTask = null;
console.log('关闭Socket')
}
export const websocetObj = {
sokcet,
stop,
sendMsg
};
在需要的页面引入
import { websocetObj } from '@/utils/websocket.js';
在方法中写入连接的方法以及回调函数
// 在onload的时候调用,创建webscoet连接对象,参数分别为:url、获取后端返回数据、监听websocket的链接失败返回的报错、监听链接状态,返回布尔值
conSocket(){
// websocetObj.sokcet(this.url,this.getWebsocetData,this.getWebsocetError,this.onErrorSucceed)
},
//websocet函数回调:返回监听的数据
getWebsocetData(val){
// val = String.fromCharCode.apply(null, new Uint8Array(val)).trim() 如果后端返回数据格式是其他的,可能需要转换一下
let info = JSON.parse(val)
info.detailShow = true
this.renwuList.push(info)
// this.scanCode = val;
},
//websocet函数抛错: 返回错误信息 用于用户提示
getWebsocetError(err){
// this.socketShow = err.isShow;
// this.webtext = err.messge;
console.log('websocet函数抛错',this.socketShow);
},
//websocet函数成功进入: 监听连接状态,在失败的时候弹窗提示,具体需求看自身情况
onErrorSucceed(val){
// this.socketShow = val.isShow;
console.log('websocet函数成功进入',val);
}
离开这个页面可以在进入的另一个页面添加关闭socekt事件
首先还是先引入websocket.js文件
import { websocetObj } from '@/utils/websocket.js';
然后在onShow()中添加
websocetObj.stop()
但是点击navBar上面的返回,不能触发小程序的生命函数
可以在App.vue中做一个全局标记,例如在onLaunch()中添加
uni.setStorageSync('openSocket',true)
表明webSocket打开了,在需要关闭socket的页面中,通过在onShow()中获取uni.getStorageSync('openSocket')判断socekt的状态,若为true,关闭socekt,将openSocket置位false。进入获取socket连接的页面再将openSocket置位ture.
二、全局监听
建立globalSocket.js
let isSocketClose=false; // 是否关闭socket
let heartbeatInterval=""; // 心跳定时器
let socketTask = null; // websocket对象
let againTimer = null;//断线重连定时器
let that = this
let url = null;
import store from '../store'
const reconnect = (url)=>{
console.log('进入断线重连',isSocketClose);
clearInterval(againTimer)//断线重连定时器
clearInterval(heartbeatInterval);
socketTask && socketTask.close(); // 确保已经关闭后再重新打开
socketTask = null;
// 连接 重新调用创建websocet方法
againTimer = setInterval(()=>{
console.log('在重新连接中...');
openWs(url)
},1000)
}
//监测链接,若是断开就重连
function checkWs(){
//心跳重连
if([2,3].includes(socketTask.readyState)){//closing 或 closed
console.log('心跳重连...')
socket.close();
socket = null;
openWs(url);
}
}
const stop = ()=>{
isSocketClose = true
clearInterval(heartbeatInterval);
clearInterval(againTimer)//断线重连定时器
socketTask.close(); // 确保已经关闭后再重新打开
socketTask = null;
console.log('关闭Socket')
}
//socket建立和监听
const openWs= (conUrl)=> {
//建立socketSocket和监听ws代码
url = conUrl
socketTask = uni.connectSocket({
url: conUrl,
success(data) {
console.log("websocket连接成功");
clearInterval(againTimer)//断线重连定时器
},
fail: (err) => {
console.log("连接报错",err);
}
});
// 连接打开
socketTask.onOpen((res)=>{
// console.log('WebSocket打开');
clearInterval(againTimer)//断线重连定时器
heartbeatInterval && clearInterval(heartbeatInterval);
// 60秒发送一次心跳
heartbeatInterval = setInterval(() => {
checkWs()
}, 10000*6)
})
// 监听连接失败
socketTask.onError((err)=>{
// console.log('WebSocket连接打开失败,请检查',err);
//停止发送心跳
clearInterval(heartbeatInterval)
//如果不是人为关闭的话,进行重连
if (!isSocketClose) {
reconnect(url)
}
})
// 监听连接关闭
socketTask.onClose((e) => {
// console.log('WebSocket连接关闭!');
// clearInterval(heartbeatInterval)
if (!isSocketClose) {
reconnect(url)
}
})
// 监听收到信息
socketTask.onMessage((res) => {
let serverData = res.data
//与后端规定好返回值分别代表什么,写业务逻辑
// serverData && onReceive(serverData);
uni.setStorageSync('dataInfo',serverData)
store.dispatch('app/set_renWuSocektData_fun', serverData)
});
}
export const websocetObj = {
stop,
openWs
};
在App.vue组件中引入
<script>
var launched = true; // onLaunch全局触发一次,再次打开用Onshow触发
import { websocetObj } from '@/utils/globalSocket.js';
import { g_config } from '@/static/global.config.js'
export default {
onLaunch: function() {
websocetObj.openWs(g_config.conUrl)
},
onShow: function() {
if(launched){
launched = false;
}else{
//建立socketSocket和监听ws代码
websocetObj.openWs(g_config.conUrl)
}
},
onHide: function() {
// console.log('App Hide')
websocetObj.stop();
console.log('关闭Socket') }
}
</script>
<style> </style>
<style lang="scss"></style>
在需要获取数据的页面添加watch,和data()函数同级
watch: {
'$store.state.app.renWuSocektData': {
handler(newVal, oldVal) {
// console.log(newVal)
if(newVal !== null){
this.getWebsocetData(newVal)
}
},
// immediate: true,
deep: true
}
},
$store.state.app.renWuSocektData使用到了vuex,下次再用一篇博客讲解vuex的使用。