Websocket-【聊天室的原理,接收消息提醒/ 公告消息】

Websocket是什么样的协议,具体有什么优点
首先,WebSocket是HTML5出的东西(协议),Websocket是一个持久化的协议, 而HTTP是一种非持久的协议
 

服务器推送消息到前端实现页面数据实时刷新项目链接如下:https://blog.csdn.net/pengff1234/article/details/114520623
 

websocket的使用步骤:

  •     建立websocket连接后,
  •     客户端(前端)可以发送指令给后端,
  •     后端如果有数据就返回,
  •     此时前端可以接收到消息,进行音频的播放

实现步骤

   1: 案例:【实现--实时接收消息提醒并语音播报】

  从此连接下载必须的js:https://gitee.com/jqn-room/case-code/tree/master/websocket/static
  sockjs.min.js 和   stomp.min.js

/*
  audio音频: 
     src:是音频路径,
     preload:是否预加载,
     muted:静音,现在浏览器不支持自动播放音频,
     autoplay:自动播放,即便音频你没有设置为静音,在页面加载的时候也不会播放音频的。
     因此先设置为静音,然后需要播放音频的时候,将音频的静音取消,然后重置音频从头开始进行播放即可。
*/

<template>
  <div id="wrap">
    <p>
      <audio src="./remind.mp3" id="audio" preload="auto" muted autoplay type="audio/mp3" controls="controls">
           <span id="audioId">播放音乐</span>
      </audio>
    </p>
  </div>
</template>
<script src="dist/js/sockjs.min.js"></script>
<script src="dist/js/stomp.min.js"></script>
<script>
  export default {
    data () {
      return : {}
    },
    methods: {
      websocket () {
         var websocket = null;
        // 1: websocket 实例化
        // 判断当前浏览器是否支持websocket
        if ("websocket" in window) {
            websocket = new WebSocket("wss://echo.websocket.org");
            //上面的这个"wss://echo.websocket.org"是从别的地方找来的,后端会提供的……,此时仅用于测试使用

           // 2: websocket建立连接
           var setIntervalWesocketPush = null;
           websocket.onopen = (e) => {
              console.log("建立连接");//建立连接后,send发送消息给后端,具体的内容可以前后端定义好,此处为"ping"
              clearInterval(setIntervalWesocketPush);//下面的代码是清理定时器,并重启定时器,每隔15s发送一次消息
              websocket.send("ping"); // 发送消息
              setIntervalWesocketPush = setInterval(() => {
                 websocket.send("ping");
              }, 15000);
           };
           //后端接收到消息后,可以发送数据给前端,前端就可以接收到了
           

           // 3: websocket 接收消息
           websocket.onmessage = (e) => {
              console.log("收到消息:" + e.data);
              // 获取音频:之前我都是用$("#audio")获取音频,但是执行:$("#audio").play()方法是会报错
              var audio = document.querySelector("audio");//用这种标签名称获取的方式就不会报错了,,,,
              audio.currentTime = 0;//从头开始播放
              audio.muted = false;//取消静音
              audio.play();//音频播放
           };

           // 4: websocket 通信错误
           websocket.onerror = (e) => {
              alert("websocket通信发生错误");
           };

           // 5: websocket 关闭连接
           websocket.onclose = (e) => {
               console.log("连接关闭");
               clearInterval(setIntervalWesocketPush);
               websocket.close(); // 关闭WebSocket连接
           };
        } else {
            alert("您的浏览器不支持websocket")
        }
      } 
    },
    mouted () {
      window.addEventListener('unload', e => this.unloadHandler(e))
      this.websocket()
    },
    destroyed() {
      window.removeEventListener('unload', e => this.unloadHandler(e))
    }
  }
</script>

   2: 案例2 【实现一个实时聊天功能】
      项目链接地址:https://gitee.com/jqn-room/case-code/tree/master/websocket/websockChat-master

问题拓展:
我想实现用户登录之后一直保持websocket连接,也就是多页面共享一个websocket,当其他户给他发信息时后端立马就转发给他,如果不在线,就存储消息,等他上线在发给他,这个功能怎么实现呢???

答: 可以在登录的时候,在根页面(或者在多页面外再包一层页面)里面建立websocket连接,后端收到消息可以先判断当前这个人是否有对应session存在,用户是否在线。

不在线可以先存redis或者数据库,等到下一次用户登录建立sockekt的时候再进行判断 和 发送。

前端通过socket收到消息再去进行对应的业务展示或者业务调用


WebSocket模拟库插件:SockJS

01 SockJS简介

  • 在传输方式的选择方面,SockJS 会优先采用 websocket,然后再自动降级;
  • 其 API 几乎与 websocket API 的使用方式相同;
  • 兼容跨浏览器,支持跨域。

      SockJS 是一个浏览器上运行的 JavaScript 库,如果浏览器 不支持 WebSocket 的情况下,也可以很简单地实现WebSocket的功能的,方法就是使用 SockJS。该库可以模拟对 WebSocket 的支持,实现浏览器和 Web 服务器之间低延迟、全双工、跨域的通讯通道。

它会 优先选择WebSocket 进行连接,但是当服务器或客户端不支持WebSocket时,会自动在 XHR流、XDR流、iFrame事件源、iFrame HTML文件、XHR轮询、XDR轮询、iFrame XHR轮询、JSONP轮询 这几个方案中择优进行连接。

幸运的是,我们不需要知道这些方案都代表什么,只需要简单地设置就可以使用了。

 实现步骤如下:

服务端-后端
启动WebSocket的配置中,你需要做的所有事情就是加上 withSockJS()


public void registerWebSocketHandlers(WebSocketHandlerRegistry) {
     // withSockJS 声明启用支持 sockJS
     webSocketHandlerRegistry.addHandler(marcoHandler(), "/echo").withSockJS();
}

客户端-前端
在客户端需要引入SockJS库,然后把 new WebSocket(url); 替换成 new SockJS(url);

SockJS类 和 WebSocket类是兼容的,所以可以直接替换

<template>
  
</template>

<script>
import SockJS from 'sockjs-client'
import Stomp from 'stompjs'
export default {
    data () {
        return {
            ws: null,
            username: '',
            identity: '',
            stompClient: null,
            userId: '',
            auctionData: {
                landId: ''
            }
        }
    },
    methods: {
        // 创建连接方法
        connection (url, headers) { // 建立连接
            // 动态的连接地址 url 和 订阅的数据 headerData
            if ('WebSocket' in window) {
                // 建立连接对象
                const socket = new SockJS(url)
                // 获取STOMP子协议的客户端对象
                this.stompClient = Stomp.over(socket)
                this.stompClient.connect(headers, this.callbackSuccess, this.callbackError)
            } else {
                alert('当前浏览器 Not support websocket')
            }
        },
        callbackSuccess () { // websocket的返回成功的方法,可在里面进行具体的监听接口和路径的配置
            console.log('建立连接成功')
            // subscribe订阅服务端提供的某个topic(主题)
            this.stompClient.subscribe('/topic/' + this.auctionData.auctionId + '/auctionStart/getResponse', (msg) => {
                // 业务操作
            })
            // subscribe订阅服务端提供的某个topic(主题)
            this.stompClient.subscribe('/topic/' + this.auctionData.auctionId + '/rotationSettlement/getResponse', (msg) => {
                // 业务操作
            })
            // subscribe订阅服务端提供的某个topic(主题)
            this.stompClient.subscribe('/topic/' + this.auctionData.auctionId + '/auctionOver/getResponse', (msg) => {
                // 业务操作
            })

            // 监听轮次完成
            this.stompClient.subscribe('/topic/' + this.auctionData.auctionId + '/rotationOver/getResponse', (msg) => {
                // 业务操作
            })

            // 完成一个流程 开启新轮询
            this.stompClient.subscribe('/user/' + this.userId + '/' + this.auctionData.auctionId + '/getResponse', (res) => {
                console.log(res + 'user')
                const result = JSON.parse(res.body)
                if (result.code === 200) {
                    this.query() // 完成后新业务逻辑,或创建新的轮询等
                } else {
                    console.log(result.msg)
                }
            })
        },
        callbackError (err) { // websocket的返回失败的方法
            console.log(err)
            this.disconnect(); // 断开连接
        },
        disconnect () { // 断开连接的方法
            console.log(this.stompClient)
            if (this.stompClient) {
                this.stompClient.disconnect()
                this.stompClient = null
            }
        },
        // 根据状态判断是否开始通信
        initConnect () {
            var url
            if (location.hostname === '192.168.10.143' ||
                location.hostname === 'localhost' ||
                location.hostname === '127.0.0.1') {
                url = 'http://121.40.115.212' // 本地测试地址
            } else {
                url = `https://${location.hostname}/proxy` // 线上地址
            }
            this.connection( // 开始连接
                `${url}/api/development/websocket/ws`,
                { name: this.userId, landId: this.auctionData.landId }
            )
        }
    },
    mounted() {
        this.initConnect()
    },
    beforeDestroy() {
        // 在页面关闭或销毁时关闭socket
        this.disconnect(); // 断开连接
    }
}
</script>

<style>

</style>

需要做的事情就是这么多

效果展示
1:   支持 WebSocket
      当浏览器 和 服务器都支持 websocket 的时候,直接使用websocket连接

2:  不支持WebSocket

不支持WebSocket的场景有:

     浏览器不支持
     Web容器不支持,如tomcat7以前的版本不支持WebSocket
    防火墙不允许
     Nginx没有开启WebSocket支持


当遇到不支持WebSocket的情况时,SockJS会尝试使用其他的方案来连接,刚开始打开的时候因为需要尝试各种方案,所以会阻塞一会儿,之后可以看到连接有异常,那就是尝试失败的情况。

为了测试,我使用Nginx做反向代理,把www.test.com指到项目启动的端口上,然后本地配HOST来达到模拟真实场景的效果。

因为Nginx默认是不支持WebSocket的,所以这里模拟出了服务器不支持WebSocket的场景。

参考资料:https://segmentfault.com/a/1190000019409827
                      

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值