> 文档中心 > 【典藏版】一文图解前端WebSocket 实时通信

【典藏版】一文图解前端WebSocket 实时通信

在这里插入图片描述


前端领域实时通信 WebSocket 是我们必须掌握的其中一个技术点,今天木鱼和大家通过案例,快速的入门WebSocket 实时通信。一🏍 届时我将代码部分,按照先后顺序,给大家通过文章的形式去分析。

木鱼也是刚刚开始了解WebSocket ,如有不对的地方,请谅解。留言区,时刻恭候大家,我们共同迈进通信工程。

为了方便大家学习,本文只展示UI组件库逻辑部分 | 样式部分 不做展示 小伙伴们可以去 👉案例源码 获取。


1、什么是WebSocket?

根据百科给出的解释是:

  • WebSocket是一种在单个TCP连接上进行全双工通信的协议。
  • WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。
  • WebSocket API也被W3C定为标准
  • WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

其实一句话就可以做出概括:它就是一种网络通信协议,很多高级功能都需要它。

2、为什么需要 WebSocket?

初次接触 WebSocket 的人,都会问想一个问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它到底能带来什么好处?

答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。

比如说:我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。

3、特点

在这里插入图片描述

服务器可以主动向客户端推送信息客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。


4、vue2案例

(1) 技术栈

  • vue-cli@3.12.1
  • Ant Design of Vue
  • vue-router
  • localStorage
  • moment
  • ws

首先我们使用的是 Ant Design of Vue 样式组件库

①安装 ant-design-vue
npm i --save ant-design-vue
②在main.js中 完整引入
import Antd from 'ant-design-vue';import 'ant-design-vue/dist/antd.css';Vue.use(Antd);

(2) 目录结构

在这里插入图片描述

(3)router.js配置

import Vue from 'vue'import Router from 'vue-router'//导入登录页import Login from './views/Login.vue'Vue.use(Router)export default new Router({  mode: 'history',  base: process.env.BASE_URL,  routes: [    //登录页    {      path: '/Login',      name: 'Login',      component: Login    },    //首页    {      path: '/',      name: 'Home',      // route level code-splitting      // this generates a separate chunk (about.[hash].js) for this route      // which is lazy-loaded when the route is visited.      component: () => import(/* webpackChunkName: "Home" */ './views/Home.vue')    }  ]})

(4) 登录 【Login.vue】

在这里插入图片描述


一💕登录布局:

在布局前,我们先构思好页面分布,良好的开端,要占据开发的一半。有思路,才会事半功倍。

在这里插入图片描述

  • 聊天室标题
  • 用户名输入框
  • 进入聊天室按钮
  • 背景界面圆角 【样式处理】
①聊天室标题
<div class="boxs">   <h1>木鱼全球·畅聊</h1></div>

在这里插入图片描述

②用户名输入框
 <a-input placeholder="请您输入用户名">      <a-icon slot="prefix" type="user" style="color: rgba(0, 0, 0, 0.25)"/> </a-input>

在这里插入图片描述

③进入聊天室按钮
 <a-button type="dashed" ghost>       <i class="iconfont icon-SEND" @click="添加进入聊天室事件👇"></i>进入聊天室 </a-button>

如何自定义图标请参考 👉如何引用阿里图标库

一💕登录逻辑:

①用户输入信息:在输入框 内绑定 v-model="username"

data中定义存储用户信息的桶

  data() {    return {      username: "",    };  },
②进入聊天室事件:@click="handleEnterBtnClick"
   //进入聊天室    handleEnterBtnClick() {     // trim() 去除用户名里的空格      const username = this.username.trim();      //如果 输入的用户名 少于3位,程序会给出提示,如果满足 则跳转至首页聊天室      if (username.length < 3) { this.$message.warning("用户名不能小于3位", 1); return;      }      //将输入的用户名 保存到本地存储      localStorage.setItem("username", username);      //跳转到首页      this.$router.push("/");    },
③针对于 本地里有或者没有用户名信息

如果有 进入首页聊天室,否则 返回登录页【首页返回的操作】

在这里插入图片描述


在这里插入图片描述

  mounted() {  //将用户信息存储在本地    const username = localStorage.getItem("username");    if (username) {      this.$router.push("/");      return;    }  },
④清除本地存储当中的信息【演示效果】

在这里插入图片描述

(5) 首页【Home.vue】

在这里插入图片描述

一💕首页布局:

在这里插入图片描述

在这里插入图片描述

  • 消息列表
  • 内容输入框
  • 发送按钮
①消息列表:
      <a-list ref="record" item-layout="horizontal" :data-source="msgList">            <a-list-item slot="renderItem" slot-scope="item"> <a-list-item-meta>   <p slot="title">        <span> {{ item.user }}</span>          <span>发送时间:{{ $moment(item.dateTime).format("YYYY-MM-DD HH:mm:ss") }}</span>   </p>      <p slot="title">会话内容:{{ item.msg }}</p>      <a-avatar slot="avatar" src="https://gw.alicdn.com/tps/TB1W_X6OXXXXXcZXVXXXXXXXXXX-400-400.png"/> </a-list-item-meta>      </a-list-item>    </a-list>

附加:关于遍历的时间格式处理 请看:vue时间格式处理(YYYY-MM-DD HH:mm:ss)

②内容输入框:
<a-input placeholder="请输入消息"/>
③发送按钮:
<a-button type="dashed" ghost><i class="iconfont icon-SEND"></i>发送</a-button>

一💕首页逻辑【WebSocket默认配置】:

首先建立WebSocket 连接,我们要知道 WebSocket 在前端工程 支持 4种属性一👇

  • open 【建立连接】
  • close 【关闭连接】
  • error 【错误信息】
  • message 【接收处理】

附加了解内容:一🍾

后端的WebSocket 支持五种:

  1. open 【建立连接】
  2. close 【关闭连接】
  3. error 【错误信息】
  4. message 【连接处理】
  5. connection 【信息处理函数】

在外部作用域调用:
在这里插入图片描述
详细WebSocket 服务链接部署 ,请看下面 (6) node 通信部署 一🎈

//调用本地的WebSocket 服务const ws = new WebSocket("ws://localhost:8000");

此时需要vue2 项目位置–》下载ws
在这里插入图片描述

npm install ws -g
①建立连接:

在mounted 生命周期内,写出 WebSocket 连接结构代码【以下属于原生写法】

注意:

  1. this.handleWsOpen【作用于调用 methods中的连接函数事件】
  2. bind(this) 【bind(this)的作用是改变this的指向】
②默认配置:
  mounted() {    //连接       ws.addEventListener("open", this.handleWsOpen.bind(this), false);    //关闭    ws.addEventListener("close", this.handleWsClose.bind(this), false);    //错误    ws.addEventListener("error", this.handleWsError.bind(this), false);    //接收处理    ws.addEventListener("message", this.handleWsMessage.bind(this), false);  },
③配置连接参数:

在methods 生命周期内 配置,它的默认参数

 methods: {}
//建立连接handleWsOpen(e) {   console.log("FE:WebSocket open", e);},
//关闭连接handleWsClose(e) {   console.log("FE:WebSocket close", e);},
 //错误信息handleWsError(e) {   console.log("FE:WebSocket error", e);},

这步很重要,作用于前端接收广播数据 一🎯

//接收数据处理 默认结构handleWsMessage(e) {   console.log("FE:WebSocket message", e);},

④刷新处理函数事件:

我们需要在mounted 生命周期中 添加 刷新页面处理函数

判断本地存储当中有没有用户名,如果有用户名 点击浏览器刷新【F5】,不做跳转,否则跳转至登录页

mounted(){   //将用户存储到本地   this.username = localStorage.getItem("username");    //判断 如果本地存储没有当前用户名 则 跳转回登录页   if (!this.username) {     this.$router.push("/Login");     return;   }}

(6) node通信部署

在这里插入图片描述


一💕初始化处理

注意:在部署前,首先必须要做初始化处理

在server 目录下 运行 npm init -y初始化
在这里插入图片描述

npm init -y

一💕监听处理

使用nodemon 插件 做监听处理函数 一👆 也是在server 目录下运行

npm install nodemon -g

一💕启用监听

package.json 文件中修改 scripts 内的参数

  • dev 【运行方式,通过npm run dev】
  • nodemon index.js 【使用监听nodemon】、【引用index.js 文件】
"scripts": {  "dev": "nodemon index.js"},

在这里插入图片描述

一💕下载 ws 库【 附属于 WebSocket】

一👆 也是在server 目录下运行

npm install ws

一💕新建index.js

①导入const Ws = require('ws');
const Ws = require('ws');//建立模块;((Ws) => {  //......主要代码 在模块内写})(Ws)
②主要WebSocket配置【主要代码】
//接口 为8000    const server = new Ws.Server({ port: 8000    });    const init = () => { bindEvent()    }    function bindEvent() { server.on('open', handleOpen) server.on('close', handleClose) server.on('error', handleError) server.on('connection', handleConnection)    }    //与前端建立连接    function handleOpen() { console.log('BE:WebSocket open');    }    //与前端关闭连接    function handleClose() { console.log('BE:WebSocket close');    }    //错误信息    function handleError() { console.log('BE:WebSocket error');    }    //信息处理    function handleConnection(ws) { console.log('BE:WebSocket connection'); ws.on('message', handleMessage)    }    //与前端建立连接    function handleMessage(msg) { //遍历每一条内容信息 server.clients.forEach((c) => {     // 发送send 信息 到前端     c.send(msg); })    }

(7) 首页添加触发事件函数

① 请输入消息框 绑定 v-model="msg"
  <a-input placeholder="请输入消息" v-model="msg"/>
  data() {    return {      msg: "",//发送的内容      username: "",//用户名      msgList: [],//消息列表数据    };  },
②发送按钮绑定事件 @click="handleSendBtnClick"
<a-button type="dashed" ghost @click="handleSendBtnClick"><i class="iconfont icon-SEND"></i>发送</a-button>
   //发送逻辑    handleSendBtnClick(e) {      if (this.msg == "") { this.$message.warning("不能发送空白消息", 1);      } else { const msg = this.msg; //去除头尾空格 if (!msg.trim().length) {   return; } //接收发送的内容 ws.send(   //将返回的数据以对象的形式 展示在前台   JSON.stringify({     id: new Date().getTime(),     user: this.username,     dateTime: new Date().getTime(),     msg: this.msg,   }) ); //输入完信息后 置空 this.msg = "";      }    },
③ 接收广播数据

在methods 中增加handleWsMessage 处理函数 接收返回的数据

   //前端接收广播数据    handleWsMessage(e) {      //数据类型转换 为对象的形式      const msg = JSON.parse(e.data);      //将输入的内容 添加到 消息列表      this.msgList.push(msg);      console.log(msg);      // console.log("FE:WebSocket message", e);    },

在这里插入图片描述
在这里插入图片描述

(8) 通信演示

在这里插入图片描述


结束:一个简单的WebSocket 案例已完成。

如果有不明白的地方,小伙伴们可以在评论区留言

在这里插入图片描述