vue项目中通过WebSocket实现实时消息提示(前端代码)

需求说明

后台有新增消息通知,并实时推送给用户端,用websocket可以很方便的解决这个问题,但是websocket有个弊端不兼容IE8,9.由于我是搞前端的所以以下都是涉及前端的代码.

实现过程
1.在前端建立连接

在methods创建websocket连接

//websocket实时获取数据
initWebSocket(){
	 if(this.websocket){
	   this.websocket.close()
	   this.websocket = null
	 }
	 this.websocket = new WebSocket(process.env.VUE_APP_WEBSOCKET_URL+'/ws/wsHandlerForFrontWithBackground');
	 // console.log(this.websocket)
	 let that = this.websocket;
	 that.onopen = this.websocketonopen;
	 that.onerror = this.websocketonerror;
	 that.onmessage = this.websocketonmessage; 
	 that.onclose = this.websocketclose;
},

创建的websocket链接含有几个回调函数

websocketonopen() { //发送成功回调
  console.log("WebSocket连接成功");
   let that = this
   window.onbeforeunload = function() {
     that.websocket.close();
   } 
 },
 websocketonerror(e) { //错误回调
   console.log(e,"WebSocket连接发生错误");
 },
 websocketonmessage(e){ //数据接收  
   // console.log(e,'数据接收')
   this.heartCheck()
   if(e.data){
     console.log(e.data)
     let data = JSON.parse(e.data).data
     if(data){
     //自己展示弹框的封装方法
       this.showNotification(data)
     }
   }
 }, 
 websocketclose(e){ //关闭 
     // 这里做了个长链接意外关闭后重新链接的操作
     console.log('关闭',e)
     let that = this
     if(!this.disconnectTimer){
       this.disconnectTimer = setTimeout(()=>{
         that.initWebSocket()
         that.disconnectTimer = null
       },1000)
     }  
     // if(e){
     //     this.websocket.close()
     //     this.websocket = null
     // }
 },
2.添加弹框

长链接建立连接的逻辑不复杂,很好完成.难点在于上连接完成后,全局弹框的展示,我的思路是在总布局的组建中添加一个弹框组件,只要收到消息就弹出.弹框的展示用的elemenUI中this.$notify()方法进行弹框,
具体的代码就不粘贴的elementui官网中有其使用方法.

3.当收到消息时,发起语音提示。
  1. 页面上需要定义一个audio,同时把这个标签隐藏
<template>
  <div>
    <audio controls="controls" hidden src="@/assets/tip.mp3" ref="audio" muted></audio>
  </div>
</template>
  1. 语音播报的方法,在消息弹框的时候调用即可,不过谷歌浏览器中在用户未完交互的情况下是会有报错的,意思是用户要对页面进行操作,例如点击后才可播放.在下边我加了一个可以检测是否播放声音的方法
// 语音播放
aplayAudio () {
 const audio = document.getElementById('audio')
 audio.play()
}
//测试是不是可以自动播放并返回结果
    testAutoPlay () {
      let autoplay = false
      return new Promise(resolve => {
        let audioPlay = this.$refs.audio
        // audioPlay.currentTime = 0; //从头开始播放提示音
        // audioPlay.muted = true;    //静音播放
        // play返回的是一个promise
        audioPlay.play().then(() => {
          // 支持自动播放
          autoplay = true;
        }).catch(err => {
          // 不支持自动播放
          autoplay = false;
        }).finally(() => {
          // 告诉调用者结果
          resolve(autoplay);
        });
      });
    },

具体解释和解决方法你可查阅这里,这里写的很详细

遇到的问题
1.长链接断开问题

针对长链接断开问题,我除了使用断开后重连的逻辑,还设置了心跳机制,在没有消息返回的时候,前端给后台循环发送数据,后台通过长链接返回数据,防止没有消息返回自动断开. 上代码

 //设置心跳机制
    heartCheck(){
      let that = this
      this.resetHeartTimer()
      if(this.timeoutObj){
        clearTimeout(this.timeoutObj);
        this.timeoutObj = null
      }
      this.timeoutObj = setTimeout(function(){
          //这里发送一个心跳,后端收到后,返回一个心跳消息,
          //onmessage拿到返回的心跳就说明连接正常
          if(that.websocket){
            that.websocket.send("ping");
          }
          // console.log("ping!")
          if(that.serverTimeoutObj){
            clearTimeout(that.serverTimeoutObj);
            that.serverTimeoutObj = null
          }
          that.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
              that.websocket.close();     //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
          }, 10000)
      }, 10000)
    },

通过心跳机制和断开重连逻辑虽然不是很完美解决断开问题,但是是我现阶段想到解决方案,如果后期发现新的解决办法再来更新方法.

2.浏览器拦截自动播放问题

针对这个问题提供两个方案
方案一: 通过检测页面是否可以自动播放的检测,可以识别是否可以播放声音在消息弹框或者页面中设置一个声音开关图标,如果不能自动播放,点击开关后自动完成交互自然可以播放,不过这种方式只要刷新页面不交互的情况下播放开关就会重置,需要重新点击.检测是否可以自动播放的方法可以查看这里
方案二: 更改浏览器设置,具体咋修改可以查看这里,修改通知里的声音提示.
希望对你有帮助

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐