在vue中使用websocket的小demo

WebSocket是HTML5下一种新的协议(协议名为"ws")。

我们常用的http协议是一种无状态协议,对于事物的处理没有记忆能力,每次请求都是独立的,而且需要浏览器主动向服务器发送请求,服务器再相应浏览器的请求。而websocket在建立连接后,可以互相主动发送请求,且无需像hhttp那样每次请求都发送一次冗长的header。

这里简单的写一个demo,认识一下websocket的使用。

场景:后端定时向前端发送时间随机颜色,前端再把这些数据实时渲染在页面上。前端也可以点击按钮向服务器端发送数据,效果如下图:

这里后端我用express,并使用express-ws提供websocket服务。

步骤0:任意处新建一个文件夹,命名为server,里面再新建一个文件server.js

步骤1:下载express、express-ws

npm i express express-ws

步骤2:启动服务器,测试是否启动成功

// server.js
// 导入
const express = require("express");
// 创建web服务器
const app = express();

// 监听请求
// 只要用户在浏览器访问http://localhost:3000/test,就会向浏览器相应下面这个h1标签
app.get("/test", (req, res) => {
  res.send("<h1>你好,express</h1>");
});

// 启动服务器,端口设置为3000
app.listen(3000, (err) => {
  if (!err) {
    console.log("服务器启动成功,监听端口3000");
  }
});

在server.js中输入以上代码,在命令行输入(进入到根目录输入)node ./server.js,回车,命令行出现以下输出,代表启动服务器成功:

        

 且在浏览器请求localhost:3000/test,出现我们预期的测试信息:

 好现在我们已经启动了一个express服务器,我们接着 在server.js加入websocket服务,完整代码如下:

// 导入
const express = require("express");
// 创建web服务器
const app = express();
const ws = require("express-ws");
// 将 ws 混入到 app中,在模块化开发时也可混入在 Router 对象中
const expressWs = ws(app);

// 监听请求
// 只要用户在浏览器访问http://localhost:3000/test,就会向浏览器相应下面这个h1标签
app.get("/test", (req, res) => {
  res.send("<h1>你好,express</h1>");
});

app.ws("/socket", (ws, req) => {
  // ws:websocket 实例,该实例可以监听来自客户端的消息发送事件
  // req:浏览器请求实例
  // 使用定时器不停的向客户端推动消息
  let timer = setInterval(() => {
    ws.send( JSON.stringify({ color: "#" + Math.random().toString(16).slice(2, 8), text: new Date(), }));
  }, 3000);

  // 监听断开连接
  ws.on("close", () => {
    console.log("本次连接已关闭");
    clearInterval(timer);
    timer = null;
  });

  // 监听浏览器发来的数据
  ws.on("message", (res) => {
    ws.send( JSON.stringify({ color: "#" + Math.random().toString(16).slice(2, 8), text: `我是浏览器端发送过来的:${res}`})
    );
    clearInterval(timer);
  });
});

// 启动服务器,端口设置为3000
app.listen(3000, (err) => {
  if (!err) {
    console.log("服务器启动成功,监听端口3000");
  }
});

以上,服务器端已准备就绪,接下来就看前端的了。

下面,先为前端代码(vue2)

<template>
  <div id="app">
    <div class="container" :style="{backgroundColor:present.color}">{{present.text}}</div>
    <button class="btn" @click="toSend">向服务器发送数据</button>
  </div>
</template>

<script>
const path = "ws://localhost:3000/socket"
export default {
  name: 'App',
  data(){
    return {
      socket:null,
      present:{
        color:'#172b4d',
        text:'默认文本'
      },
      heartCheck:{
        timeout: 1000*60*5, //五分钟心跳一次
        timer:null,
        serverTimer:null,
        reset:()=>{
          clearTimeout((this.heartCheck.timer))
          clearTimeout((this.heartCheck.serverTimer))
          return this.heartCheck
        },
        start:()=>{
            this.heartCheck.serverTimer = setInterval(()=>{
              if(this.socket.readyState===1){
                console.log('虽然没有发送消息,但是现在是连接状态');
                this.socket.send('socket heart')
                this.heartCheck.reset().start()
              }else{
                console.log('已断开连接,尝试重连吧');
                this.socketReconnect()
              }
          },this.heartCheck.timeout)
        }
      },
      reconnectTimer:null,// 重连计时器
      reconnectLock:false// 重连的锁
    }
  },
  mounted(){
    if (typeof (WebSocket) === 'undefined') { console.error('浏览器不支持WebSocket'); return; }
    try {
      this.initSocket()
    } catch (error) {
      // 重连
      console.log('出来');
      this.socketReconnect()
    }
  },
  beforeDestroy(){
    this.socket.close()
  },
  methods:{
    initSocket(){
      this.socket = new WebSocket(path)
      this.socket.onopen = this.openHandler // 连接成功建立的回调
      this.socket.onmessage = this.messageHandler // 接收到消息的回调
      this.socket.onerror = this.errorHandler // 连接发生错误的回调
      this.socket.onsend = this.sendHandler // 向后端发送数据的回调
      this.socket.onclose = this.closeHandler // 连接关闭的回调
      
      window.onbeforeunload = () => {
        this.socket.close()  // 窗口关闭时主动断开请求 
      };
    },
    socketReconnect(){
      if (this.reconnectLock) {
          return;
      }
      this.reconnectLock = true
      this.reconnectTimer && clearTimeout(this.reconnectTimer);
      this.reconnectTimer = setTimeout(() => {
          console.log("WebSocket:重连中...");
          this.reconnectLock = false;
          // websocket启动
          this.initSocket();
        }, 4000);
    },
    // 连接成功
    openHandler(){
      this.heartCheck.reset().start();// 建立心跳
    },
    // 接收到服务器信息
    messageHandler(res){
      this.present.color = JSON.parse(res.data).color
      this.present.text = JSON.parse(res.data).text
      this.heartCheck.reset().start() // 初始化心跳时间并重新开始心跳。如果能正常通信,无须心跳检测
    },
    // 连接错误,重连
    errorHandler(){
      console.log('错误');
      this.socketReconnect()
    },
    // 向后端发送数据的回调
    sendHandler(){},
    // 连接关闭的回调
    closeHandler(){
      this.heartCheck.reset();
    },
    // 带年纪按钮触发,向服务器发送数据
    toSend(){
      this.socket.send('我是浏览器端发送的数据')
    }
  }
}
</script>

<style lang="scss">
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
#app {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  gap: 20px;
  width: 100vw;
  height: 100vh;
  .container {
    width: 500px;
    height: 310px;
    text-align: center;
    word-wrap: break-word;
    word-break: normal;
    line-height: 310px;
    font-size: 23px;
    font-weight: 600;
    color: #fff;
    background-color: tomato;
  }
  .btn {
    padding: 8px 12px;
    border: none;
    background-color: #0052cc;
    color: #fff;
    font-size: 12px;
    border-radius: 4px;
    &:hover {
      background-color: darken($color: #0052cc, $amount: 20%);
    }
    &:active {
      background-color: #0052cc;
    }
  }
}
</style>

这样启动vue项目,websocket就会自动连上了。当我们关闭服务端时,会按照我们设置的时间间隔不断重连。

 如此小demo就大功告成啦。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值