【websocket功能】vue简单实现websocket链接模板,建立websocket心跳重连机制【包含node.js后台代码,可以自己测试websocket】

news/2024/7/24 7:38:03 标签: vue.js, websocket, node.js, 前端, 心跳重连

前言

目前很多项目需要用到websocket功能
简单的讲解一下这个功能。
简单来说就是,以往我们发请求只能前台给后台发
但是如果我们遇到比如类似聊天一样的功能,别人发信息给我。
我们就处理起来很麻烦,当然也有办法,就是我们前端设置定时器
定时请求后台拿到别人发给我的信息。
但是很明显,这不是一个好办法,如果一秒一请求,那服务器顶不住,毕竟用户不是你一个。
如果间隔时间久了,那别人发个信息给你,你都半天看不到,那还有人用你的软件吗。
所以这时候就出现了websocket。他可以让前端和后端建立长链接。保持通信状态。
不需要前端发请求,后端也可以自己把别人发来的信息推送到你前台。这就是方便多了。

看了网上很多人的帖子都是只有单独的,所以我这里再开一个前后端都有的websocket模板,可以复制即用,后端采用了node.js这样方便前端的小伙伴看得懂。而且很简单操作,复制了就可以自己测试websocket功能,不需要依靠公司后端了。

效果图

心跳后端返回ok
在这里插入图片描述
心跳
在这里插入图片描述
我发送的信息后端返回给我了。
在这里插入图片描述
心跳重连机制,如果链接失败或者错误,一直重连,直到链接成功为止
在这里插入图片描述

前端代码

vue直接复制

<template>
  <!-- websocketceshi -->
  <div class="layout">
    <div style="margin:20px;font-size:20px">websocket连接模板 有心跳重连机制</div>
    <div class="msgBody">
      <p v-for="(item, index) in msg" :key="index">{{ item }}</p>
    </div>
    <input
      v-model="inputMsg"
      style="width: 200px; height: 30px; margin-top: 20px"
    />
    <button @click="sendMessage" style="width: 100px; height: 30px">
      发送
    </button>
    <button @click="msg = []" style="width: 70px; height: 30px">清空</button>
  </div>
</template>

<script>
export default {
  name: "LayOut",
  data() {
    return {
      ws: null, //建立的连接
      lockReconnect: false, //是否真正建立连接
      timeout: 10 * 1000, //30秒一次心跳
      timeoutObj: null, //心跳心跳倒计时
      serverTimeoutObj: null, //心跳倒计时
      timeoutnum: null, //断开 重连倒计时
      wsUrl: "ws://localhost:8888", //后台websocket连接地址
      msg: [], //信息列表
      inputMsg: "", //输入
    };
  },
  created() {
    this.initWebpack();
  },
  beforeDestroy() {
    // 离开页面后关闭连接
    this.ws.close();
    // 清除时间
    clearTimeout(this.timeoutObj);
    clearTimeout(this.serverTimeoutObj);
  },
  methods: {
    // 初始化websocket链接
    initWebpack() {
      this.ws = new WebSocket(this.wsUrl);
      this.ws.onopen = this.onopen;
      this.ws.onmessage = this.onmessage;
      this.ws.onclose = this.onclose;
      this.ws.onerror = this.onerror;
    },
    //重新连接
    reconnect() {
      var that = this;
      if (that.lockReconnect) {
        return;
      }
      that.lockReconnect = true;
      //没连接上会一直重连,设置延迟避免请求过多
      that.timeoutnum && clearTimeout(that.timeoutnum);
      that.timeoutnum = setTimeout(function () {
        that.initWebpack(); //新连接
        that.lockReconnect = false;
      }, 5000);
    },
    //重置心跳
    reset() {
      var that = this;
      clearTimeout(that.timeoutObj); //清除心跳倒计时
      clearTimeout(that.serverTimeoutObj); //清除超时关闭倒计时
      that.start(); //重启心跳
    },
    //开启心跳
    start() {
      var self = this;
      self.timeoutObj && clearTimeout(self.timeoutObj); //心跳倒计时如果有值就清除掉,防止重复
      self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj); //超时关闭倒计时如果有值就清除掉,防止重复
      //然后从新开一个定时器
      self.timeoutObj = setTimeout(function () {
        //这里通过readyState判断链接状态,有四个值,0:正在连接,1:已连接,2:正在断开,3:已经断开或者链接不成功
        if (self.ws.readyState == 1) {
          //如果连接正常,给后天发送一个值,可以自定义,然后后台返回我们一个信息,我们接收到后会触发onmessage方法回调
          self.ws.send("ping");
        } else {
          //如果检测readyState不等于1那也就代表不处在链接状态,那就是不正常的,那就调用重连方法
          self.reconnect();
        }
        //从新赋值一个超时计时器,这个定时器的作用:当你触发心跳的时候可能会出现一个情况,后台崩了,前台发了个心跳,没有回应,就不会触发onmessage方法
        //所以我们需要在这个心跳发送出去了后,再开一个定时器,用于监控心跳返回的时间,比如10秒,那么10秒内如果后台回我了,触发onmessage方法,自然就会把心跳时间和超时倒计时一起清空掉
        //也就不会触发这个关闭连接,但是如果10秒后还是没有收到回应,那么就会触发关闭连接,而关闭连接方法内又会触发重连方法,循环就走起来了。
        self.serverTimeoutObj = setTimeout(function () {
          //如果超时了就关闭连接
          self.ws.close();
        }, self.timeout);
      }, self.timeout);
    },
    //连接成功
    onopen() {
      console.log("连接成功");
      if (this.ws.readyState == 1) {
        //如果连接正常,给后天发送一个值,可以自定义,然后后台返回我们一个信息,我们接收到后会触发onmessage方法回调
        this.ws.send("链接成功后先发给后台的信息");
      }
      this.start(); //链接成功后开启心跳
    },
    //接受后台信息回调
    onmessage(e) {
      /**这里写自己的业务逻辑代码**/

      this.msg.push(e.data);
      console.log("收到后台信息");
      this.reset(); //收到服务器信息,心跳重置
    },
    //关闭连接回调
    onclose(e) {
      console.log("连接关闭");
      this.reconnect(); //重连
    },
    //连接异常回调
    onerror(e) {
      console.log("出现错误");
      this.reconnect(); //重连
    },
    //发送消息
    sendMessage() {
      this.ws.send(this.inputMsg); //把前台的信息发给后台(可以跟后端商量传什么数据结构,一般不是这样简单的一个字符串,都是json格式的)
      this.inputMsg = "";
    },
  },
};
</script>
<style scoped>
.layout {
  position: relative;
  width: 100%;
  height: 100%;
}
.msgBody {
  width: 500px;
  height: 300px;
  border: 1px solid rgb(95, 79, 79);
  overflow: auto;
}
</style>


后端部分项目创建

没有下载node的下载一下,没有淘宝镜像的可以下载一下淘宝镜像,方便后面下载。

1.安装node.js,自行官网下载,前端人员应该都有下载node。如果要看是否下载直接cmd输入 node -v查看版本
2.安装cnpm 安装命令 :npm install -g cnpm --registry=https://registry.npm.taobao.org

查看命令 :cnpm -v

然后按照步骤来:
1,创建一个文件夹,然后在里面写一个文件,名字叫 express-run.js 把这个代码复制进去就行了,这个代码包含了get和post请求,以及websocket。所以前端小伙伴也可以用这个后台测试一下接口

var express = require("express"); //导入express  (下载)
var app = express();
var bodyParser = require("body-parser"); //导入body-parser  (下载)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

// 跨域设置
var allowCrossDomain = function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*'); //自定义中间件,设置跨域需要的响应头。
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); //允许任何方法
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,X-Session-Token'); //允许任何类型
    next();
};
app.use(allowCrossDomain);

//模拟信息
dataInfo = [
    { name: "苹果", count: 0, price: 10.01, check: false, },
    { name: "桃子", count: 0, price: 22.11, check: false, },
    { name: "橘子", count: 0, price: 8.12, check: false, },
]
//get方法  前台请求地址:http://127.0.0.1:3000/list/fruitsData
app.get('/list/fruitsData', (req, res) => {
    res.status(200),
        res.send({ code: 200, describe: "success", data: dataInfo })
})

//post方法  前台请求地址:http://127.0.0.1:3000/user/login
app.post('/user/login', (req, res) => {
    var { username, password } = req.body
    console.log(req.body);
    if (username != "xq" || password != "xq123") {
        return res.send({ code: 404, describe: "用户名或密码不正确" })
    } else {
        return res.send({ code: 200, describe: "success", data: { username, password } })
    }
})

//websocket
const WebSocketServer = require('ws').Server

const wss = new WebSocketServer({ port: 8888 }) //服务端口8888
var player = new Array()
console.log('创建ws服务', 'ws://localhost:8888')
// 创建连接
wss.on("connection", ws => {
    id = gid();
    player.push(id)
    console.log("新客户端已连接")
    // 接收到 client 数据时
    ws.on("message", data => {
        //前台传ping就返回ok
        if (data == 'ping') {
            ws.send('ok')
            return
        }
        //群发
        wss.clients.forEach(s => {
            if (s.readyState == 1 && s.socketIdxos != id) {
                s.send(data)
            }
        })
    })
    ws.on("close", () => {
        console.log("websocket server: 客户端已关闭连接")
        player = new Array()
    })
    ws.onerror = function () {
        console.log("websocket server: 出错了")
    }
})
//给用户设定一个id
function gid() {
    var id = Math.floor(Math.random() * (99999999 - 10000000 + 1)) + 10000000
    var have = false;
    for (var i = 0; i < player.length; i++) {
        if (player[i] == id.toString()) {
            have = true;
            break;
        }
    }
    if (have) {
        gid();
    } else {
        return id;
    }
}


const port = process.env.PORT || 3000  //端口
const host = process.env.HOST || '127.0.0.1' //地址
//运行中
app.listen(port, host, () => {
    console.log(`Server is running on http://127.0.0.1:3000`);
});

2,安装依赖 cnpm install -S express body-parser
3,安装package.json 安装命令 npm init -y

然后就可以了。直接启动就行了。
启动方式很简单。

启动方式:和前端启动方式一样,这里一般默认的是start 那你启动就npm run start
但是我改成了dev,这是我的习惯,所以我的启动方式就是npm run dev
然后当下面出现了Server is running on http://127.0.0.1:3000这句话就代表后台启动成功正在运行了,这句话是log出来的,可以自己改别的也行。
如果你想结束运行,也是和前台一样ctrl+c按两下就行。
在这里插入图片描述
这是项目的结构
在这里插入图片描述


http://www.niftyadmin.cn/n/490460.html

相关文章

【html转pdf】html页面导出为pdf文件,纯html版本,简单实现pdf转换【html2canvas+jspdf】

前言 最近遇到的需求&#xff0c;把html转成pdf文件下载导出。 目前网上看了下&#xff0c;有三种方法&#xff0c;但是其中两种需要后端配合 一种是纯前端实现的&#xff0c;比较简单。所以就使用了这种。 也就是html2canvas jspdf 的这种方法 这种方法实现的思路就是&#…

windows10强制删除文件_可能是最后一次机会,2 种方法免费升级到 Windows 10

根据微软公布的信息&#xff0c;十年前发布的 Windows 7 将于 2020年 1月14 日正式结束「扩展支持」&#xff0c;而与之相对的「主流支持」也在 2015 年 1 月 13 日就已经结束。相比此前 Windows XP 的生命周期&#xff0c;Windows 7 的生命周期并未获得延长&#xff0c;毕竟其…

苹果手机自带表格软件_手机系统自带软件不用却卸载不了,如何才能解决这个问题?...

手机系统自带软件不用却卸载不了&#xff0c;如何才能解决这个问题&#xff1f;很多人对于安卓手机中自带的软件非常头疼&#xff0c;因为很多预装软件你用不上&#xff0c;又不能卸载&#xff0c;它们还会自动联网&#xff0c;会在你不知道的情况下&#xff0c;耗费流量&#…

lateX 编译中文_【小白向】LaTeX 中文入门

注&#xff1a;本文尚未撰写完毕&#xff0c;先暂存一下~(2020/06/27)参考学习路线[1]如何从零开始&#xff0c;入门 LaTeX&#xff1f; 孟晨 1. 卸载 CTeX 套装&#xff0c;安装 TeX Live原因及教程见&#xff1a;TeX Live 下载及安装说明2. 看完&#xff1a;一份其实很短的 L…

大数据杀熟 算法_大数据杀熟这事,究竟有多没谱?

同一时间&#xff0c;打开不同手机查看同一航班机票&#xff0c;价格为何相差近千元?在线旅游平台背后的“大数据杀熟”近年来逐渐为人熟知。9月中旬&#xff0c;央视新闻在微博上发起投票“你遭遇过大数据杀熟吗”&#xff0c;勾选“遇到过&#xff0c;价格差异明显”的用户有…

博图注册表删除方法_回收站被清空文件删除的恢复方法

前几天一个同事不小心删除了回收站里的文件&#xff0c;但是想起来还有用&#xff0c;但是怎么也找不回来了&#xff0c;着急半天&#xff0c;最后我给他恢复回来&#xff0c;高兴坏了。今天就来说说回收站文件删除后恢复的方法。很多人在碰到不需要的文件时都是选择删除掉&…

人脸反光识别和读数识别_树莓派人脸识别实际应用:人脸识别门禁

2020-3-16 之前舵机开门关门逻辑有点混乱&#xff0c;不合乎常理&#xff0c;现对树莓派人脸识别代码进行修改&#xff0c;以及Arduino控制代码有所调整&#xff1b;在上一篇文章树莓派调用百度人脸识别API实现人脸识别&#xff0c;我们完成了树莓派人脸识别的基础环境配置&…

信捷plc485通信上位机_STM32L476R快速入门——串口与上位机通信

串口通信由两种方式&#xff0c;第一种就是用微机原理课上学过的TX和RX两个接口进行通信。不过根据去年的经验&#xff0c;这个板子直接用TX和RX两个接口进行通信容易被烧坏&#xff0c;所以我们就用更简单的usb通信。在发stm32的时候&#xff0c;老师会给你一个usb的供电线&am…