Vue 中前后端使用WebSocket

这篇具有很好参考价值的文章主要介绍了Vue 中前后端使用WebSocket。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是websocket

  • WebSocket 是一种网络通信协议。RFC6455定义了它的通信标准。

  • WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)

  • 它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的

  • http是一种无状态,无连接,单向的应用层协议,它采用了请求/响应模型,通信请求只能由客户端发起,服务端对请求做出应答处理。这样的弊端显然是很大的,只要服务端状态连续变化,客户端就必须实时响应,都是通过javascript与ajax进行轮询,这样显然是非常麻烦的,同时轮询的效率低,非常的浪费资源(http一直打开,一直重复的连接)。

  • 于是就有了websocket,Websocket是一个持久化的协议,它是一种全面双工通讯的网络技术,任意一方都可以建立连接将数据推向另一方,websocket只需要建立一次连接,就可以一直保持

websocket 原理

  • websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信

  • 在websocket出现之前,web交互一般是基于http协议的短连接或者长连接

  • websocket是一种全新的协议,不属于http无状态协议,协议名为"ws"

  • 说它是TCP传输,主要体现在建立长连接后,浏览器是可以给服务器发送数据,服务器也可以给浏览器发送请求的。当然它的数据格式并不是自己定义的,是在要传输的数据外层有ws协议规定的外层包的。

websocket与http的关系

  • 相同点:

  • 都是基于tcp的,都是可靠性传输协议,都是应用层协议

  • 不同点:

  • WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息

  • HTTP是单向的

  • WebSocket是需要浏览器和服务器握手进行建立连接的

  • 而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接

  • 联系

  • WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的

  • 关系图

websocket前后端交互,vue 性能优化-项目适配问题,# websocket使用,websocket,vue.js,服务器,网络协议

websocket前后端交互,vue 性能优化-项目适配问题,# websocket使用,websocket,vue.js,服务器,网络协议

实际开发

  • 我们有一个需求就是报警数据来了之后在前端报警处理,不使用websocket就只能通过轮询每3秒调用一次接口,在吧查回来的数据进行判断,如果多了就开始调接口继续操作,这样很浪费资源。

  • 使用websocket之后,建立连接之后。后端察觉数据变化之后,通过他的send方法通知前端,前端通过onmessage提示调用,可以在里面直接调用查询数据接口继续操作。

  • 我们这里是建立连接通过他数据变化后端通知前端,前端有个方法会执行,我们在这个方法里面调用我们查询接口,也可以是后端把这条数据发回来我们处理,根据实际情况而定。

后端代码

我们后端是做了容器化的分布式的,主要代码如下

public class WebSocketConfig {
    /**
     * 如果使用Springboot默认内置的tomcat容器,则必须注入ServerEndpoint的bean;
     * 如果使用外置的web容器,则不需要提供ServerEndpointExporter,下面的注入可以注解掉
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}


public class WebSocketServer {
​
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
​
    private static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
    //用来存放每个客户端对应的WebSocket对象。
    private static Map<String,Session> sessionPool = new HashMap<>();
​
    /**
     * 连接成功后调用的方法
     * @param session
     * @param key
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("key") String key) throws IOException {
        //key为前端传给后端的token
        this.session = session;
        //从token中获取到userid当做区分websocket客户端的key
        Long userId = JwtHelper.getUserId(key);
        sessionPool.put(String.valueOf(userId),session);
        if (sessionPool.get(String.valueOf(userId))==null){
            webSockets.add(this);
        }
        webSockets.add(this);
        System.out.println("webSocket连接成功");
        System.out.println("WebSocket有新的连接,连接总数为:"+webSockets.size());
    }
​
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSockets.remove(this);
        System.out.println("webSocket连接关闭");
    }
​
    /**
     * 收到客户端消息后调用的方法,根据业务要求进行处理,这里就简单地将收到的消息直接群发推送出去
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) {
        //心跳检测
        int beginIndex = 10;
        if ("HeartBeat".equals(message.substring(0,9))){
            String token = message.substring(beginIndex);
            System.out.println("token1"+token);
            if (!"".equals(token)){
                System.out.println("token2"+token);
                Long userId = JwtHelper.getUserId(token);
                sendTextMessage(String.valueOf(userId),"ok");
            }
        }
        System.out.println("WebSocket收到客户端消息:"+message);
    }
    /**
     * 发生错误时的回调函数
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }
​
    /**
     * 实现服务器主动推送消息
     */
    //单点消息发送
    public void sendTextMessage(String key,String message){
        Session session = sessionPool.get(key);
        if (session!=null){
            try {
                session.getBasicRemote().sendText(message);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
​
}

前端代码

1.在src/utils 建立websocket.js 引入文件,这个websocket是全局的,通过登录,和退出控制,在哪儿页面都可以使用。

// 信息提示
import { Message } from 'element-ui'
// 引入用户id
import { getTenantId, getAccessToken } from '@/utils/auth'

// websocket地址
var url = 'ws://192.168.2.20:48081/websocket/message'
// websocket实例
var ws
// 重连定时器实例
var tt
// websocket重连开关
var websocketswitch = false

// websocket对象
var websocket = {
  // websocket建立连接
  Init () {
    // 判断浏览器是否支持websocket
    if (!'WebSocket' in window) {
      this.$modal.msgError('您的浏览器不支持WebSocket')
      return
    }
    console.log('getTenantId()', getTenantId())
    // 获取用户id
    let userId = getTenantId()
    // 创建websocket实例
    ws = new WebSocket(url + '?userId=' + userId)
    // 监听websocket连接
    ws.onopen = function () {
      Message({
        type: 'success',
        message: 'websocket连接成功'
      })
    }
    // 监听websocket连接错误信息
    ws.onerror = function (e) {
      console.log('重连开关', websocketswitch)
      console.log('数据传输发生错误', e)
      Message({
        message: 'websocket传输发生错误',
        type: 'error'
      })
      // 打开重连
      reconnect()
    }
    // 监听websocket接受消息
    ws.onmessage = function (e) {
      console.log('接收后端消息:' + e.data)
      //心跳消息不做处理
      if (e.data === 'ok') {
        return
      }
      Message({
        message: e.data,
        type: 'success'
      })
    }
  },
  // websocket连接关闭方法
  Close () {
    //关闭断开重连机制
    websocketswitch = true
    ws.close()
  },
  // websocket发送信息方法
  Send (data) {
    // 处理发送数据JSON字符串
    let msg = JSON.stringify(data)
    // 发送消息给后端
    ws.send(msg)
  },
  // 暴露websocket实例
  getwebsocket () {
    return ws
  }
}

// 监听窗口关闭事件,当窗口关闭时-每一个页面关闭都会触发-扩张需求业务
window.onbeforeunload = function () {
  console.log('测试方法执行了')
}

// 浏览器刷新重新连接
// 刷新页面后需要重连-并且是在登录之后
if (window.performance.navigation.type == 1 && getAccessToken()) {
  console.log('浏览器刷新了')
  //刷新后重连
  websocket.Init()
}
// 重连方法
function reconnect () {
  console.log('重连开关', websocketswitch)
  // 判断是否主动关闭连接
  if (websocketswitch) {
    return
  }
  // 重连定时器-每次websocket错误方法onerror触发他都会触发
  tt && clearTimeout(tt)
  tt = setTimeout(function () {
    console.log('执行断线重连...')
    websocket.Init()
    websocketswitch = false
  }, 4000)
}

// 暴露对象
export default websocket

2.在登录和退出的时候进行websocket进行建立连接和关闭连接,就是在vuex(src/store/modules/user.js)调用这里方法(详细的Vuex做登录主页文章会有)。

// 引入外部文件
import websocket from '@/utils/websocket'
// 请求
const actions = {
  // 登录
  async login (ctx, data) {
    // 调用mutations里的方法存到state
    // 登录成功后创建websocket连接
    // res.data 是token
    websocket.Init(res.data)
    ctx.commit('SET_TOKEN', res.data)
  },
 
  // 退出登录
  logout (ctx) {
   // 主动关闭连接
    websocket.onClose()
    Message.success('退出成功,请重新登录')
  }
}

3.在需要用到websocket使用,我们这里是在首页使用。

// 引入websocket文件
import websocket from '@/utils/websocket'
​
// 登录成功一进到页面的时候调用
created() {
   this.getWebSocket()
 },
​
// getWebSocket()方法
method: {
   // websocket 接受消息
    getWebSocket() {
      // websocket.getWebSocket()这个是websocket里面方法返回ws对象(websocket.js)
      let ws = websocket.getWebSocket()
      // 通过ws这个对象获取这个websocket里面后端推消息前端执行的方法onmessage。
      // 给他赋给我们自己方法 this.websocketonmessage
     websocketonmessage(e)就会执行
      ws.onmessage = this.websocketonmessage
    },
    //接收到消息的回调函数
    websocketonmessage(e) {
      // e后端传回来参数
      // console.log(e.data);
      // 防止心跳监测,返回来的ok 对方法执行的影响(心跳监测方法也会执行一次)
      if (e.data == 'ok') {
        //心跳消息不做处理
        return
      }
      // 需要监测的接口 我们查询数据的接口 在进行处理
        this.alarmerlist()
    },
}
​

细节:这样登录创建连接之后,后端察觉到数据变化,就通过他的send方法给我们推消息我们前端websocket.js文件的onmessage这个方法会自己调用执行并会接受参数。我们在需要的页面引入websocket使用。把它赋值我们自己写的方法,这样数据一变化我们就会调用一次查询接口,进行处理,大大节约性能(http要用轮询一直调用查询接口)。


总结:

经过这一趟流程下来相信你也对 Vue 中前后端使用WebSocket 有了初步的深刻印象,但在实际开发中我 们遇到的情况肯定是不一样的,所以我们要理解它的原理,万变不离其宗。加油,打工人!

什么不足的地方请大家指出谢谢 -- 風过无痕文章来源地址https://www.toymoban.com/news/detail-821989.html

到了这里,关于Vue 中前后端使用WebSocket的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 实现vue项目和springboot项目前后端数据交互

    太高版本的win7不支持 这里安装node-v12.16.2-x64.msi,指定安装位置后直接按下一步就可以。 npm是node内置的工具 这里配置npm的镜像cnpm(提高下载速度,以后用到npm的命令都可以用cnpm命令替换)不指定cnpm版本使用如下命令会报错: 错误信息: 检查错误,参照网上的对应版本图,

    2024年04月25日
    浏览(37)
  • 115.【SpringBoot(IDEA)+Vue(Vscode)前后端交互】

    在SpringBoot+Vue的整合项目中我们使用的编译软件分别有: Vscode来编写Vue脚手架和IDEA来编写SpringBoot。vue脚手架是3.0以上的。 1.App.vue 这里的router-view一定要写出来,因为我们最终呈现到App.vue这个组件中去的 2.src/pages/Login.vue 将前端数据传递给后端,后端并响应的操作 3.src/pages/I

    2024年02月12日
    浏览(37)
  • nginx开启Gzip压缩,Vue性能优化之使用gzip压缩打包

    不管是vue项目还是react项目在使用webpack打包之后都会生成一个动辄一两兆甚至更大的js文件,在某些情况下严重影响项目性能,打开页面的时候白屏时间会很长,本文将介绍如何使用gzip压缩打包,主要是nginx部署的配置,非常重要,我查阅了很多文章基本都没用说清楚甚至错

    2024年02月02日
    浏览(44)
  • 基于Vue和Element UI实现前后端分离和交互

    目录 前言 一、Element UI简介 1.Element UI是什么 2.Element UI的特点 二、项目搭建 1.创建一个SPA项目 2.安装 Element-UI 3.导入组件 4.创建登陆注册界面 登录组件---Login.vue 注册组件---Register.vue 定义组件与路由的对应关系 效果演示:  三、前后端数据交互 1.安装axios 2.导入api模块,添加

    2024年02月08日
    浏览(51)
  • vite+vue3+ts搭建项目八(打包性能优化三:使用CDN)

    使用vite-plugin-cdn-import 下载npm包 官方github:https://github.com/MMF-FE/vite-plugin-cdn-import 开发环境使用本地的npm包,cdn是打包时候才生效 在vite.config.ts中通过importToCDN引入 注意事项 :网上很多教程,还需要在 build 的 rollupOptions 添加对应的 external ,如上注释所示,其实是不需要的,

    2024年02月02日
    浏览(103)
  • vue-element-ui前后端交互实现分页查询

    大体思路: ①添加element-ui分页组件 ②在data里定义几个参数用来存放当前页,每页条数,条目总数以及存放后端分页查询的结果 ③后端使用分页查询,controller层接收当前页以及每页条数的参数 ④前端编写方法发送请求到controller层调用分页查询的方法,并传参当前页及每页

    2024年01月19日
    浏览(44)
  • 【vite+vue3.2 项目性能优化实战】使用vite-plugin-cdn-import进行CDN加速优化项目体积

    CDN (Content Delivery Network)即内容分发网络,是一种通过在全球范围内分布式部署服务器来加速网络内容传输的技术。CDN加速的原理是,当用户请求访问某个资源时, CDN会根据用户的地理位置和网络状况,自动选择离用户最近的服务器来响应请求 。如果该服务器上已经缓存了

    2024年02月03日
    浏览(55)
  • (九)axios前后端跨域数据交互--基于SpringBoot+MySQL+Vue+ElementUI+Mybatis前后端分离面向小白管理系统搭建

    在任务六中我们讲过,前后端跨域数据交互,有两种方式可以解决跨域请求,任务六我们使用了CorsConfig类配置跨域。本次任务,我们使用一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中的axios,实现前后端跨域数据交互。通过本次任务,大家能够: (1)掌握axios的使用

    2024年02月15日
    浏览(38)
  • 性能优化之--- 项目打包优化(vue)

    项目体积小也是优化性能的一个方向,这里以 Vue 工程为例; 当刚运行项目的时候,发现刚进入页面,就将所有的js文件和css文件加载了进来,这一进程十分的消耗时间。 如果打开哪个页面就对应的加载响应页面的js文件和css文件,那么页面加载速度会大大提升。 vue官方文档

    2024年02月09日
    浏览(48)
  • vue - 常见的性能优化

    1, v-for 遍历避免同时使用 v-if 在 Vue2 中 v-for 优先级更高,所以编译过程中会把列表元素全部遍历生成虚拟 DOM,再来通过 v-if 判断符合条件的才渲染,就会有多余的逻辑判断和造成性能的浪费,因为我们希望的是不符合条件的虚拟 DOM都不要生成; 1,为了过滤一个列表中的项

    2024年02月16日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包