微信小程序创建WebSocket链接使用到了uni.connectSocket(OBJECT)

这里主要讲一下单页面监听(局部监听)和多页面监听(全局监听)

wireshark 微信小程序 小程序websocket连接wss_提示框

 

 

:小程序中必须是 wss:// 协议

  • 微信小程序平台1.7.0 及以上版本,最多可以同时存在5个WebSocket 连接。老版本只支持一个socket连接

wireshark 微信小程序 小程序websocket连接wss_提示框_02

 

 

先来了解一下小程序的生命周期(只显示了主要的)

wireshark 微信小程序 小程序websocket连接wss_Data_03

 

 

 一、局部监听

在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
 };

在需要的页面引入

wireshark 微信小程序 小程序websocket连接wss_提示框_04

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上面的返回,不能触发小程序的生命函数

wireshark 微信小程序 小程序websocket连接wss_连接失败_05

 

 

 可以在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的使用。