微信小程序创建WebSocket链接使用到了uni.connectSocket(OBJECT)
这里主要讲一下单页面监听(局部监听)和多页面监听(全局监听)
在各个小程序平台运行时,网络相关的 API 在使用前需要在【微信公众平台】配置域名白名单。注意:小程序中必须是 wss://
协议
先来了解一下小程序的生命周期(只显示了主要的)
一、局部监听
在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:消息监听的回调 * one rrorEvent:抛出错误的回调,且弹窗连接失败的提示框 * one rrorSucceed:抛出成功回调,主要用于隐藏连接失败的提示框 * */ const sokcet= (sockeUrl,onReceive,onErrorEvent,onErrorSucceed)=> { url = sockeUrl; onReFn= onReceive; onErrFn= one rrorEvent; onSucFn= one rrorSucceed; 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)//断线重连定时器 one rrorSucceed({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; one rrorEvent({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函数成功进入: 监听连接状态,在失败的时候弹窗提示,具体需求看自身情况 one rrorSucceed(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的使用。 参考代码:http://www.javashuo.com/article/p-qhmvfmbv-gk.html