一文图解前端WebSocket 实时通信
💌 作者简介
- 📖 个人介绍:小伙伴们,大家好!我是水香木鱼,【
前端领域创作者
】😜 - 📜 CSDN主页:水香木鱼
- 📑 个人博客:陈春波
- 🎨 系列专栏:网络通信
- 🌹 一键四连:关注💋+点赞👍+收藏⭐+留言📝
- 📢 人生箴言:即使没有万全准备,也要勇敢迈出第一步。
在
前端领域
,实时通信 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">
<!--Ant 组件 默认的循环遍历数据结构 不可更改-->
<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 支持五种:
- open 【建立连接】
- close 【关闭连接】
- error 【错误信息】
- message 【连接处理】
- connection 【信息处理函数】
在外部作用域调用:
详细WebSocket 服务链接部署 ,请看下面 (6) node 通信部署
一🎈
//调用本地的WebSocket 服务
const ws = new WebSocket("ws://localhost:8000");
此时需要vue2 项目位置–》下载ws
npm install ws -g
①建立连接:
在mounted 生命周期内,写出 WebSocket 连接结构代码【以下属于原生写法】
注意:
this.handleWsOpen
【作用于调用 methods中的连接函数事件】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 实时通信的案例】
,希望可以帮到大家,谢谢。
如果您觉得这篇文章有帮助到您的的话不妨【关注+点赞+收藏+评论+转发
】支持一下哟~~😛您的支持就是我更新的最大动力。👇👇👇👇👇👇
🛩往期精彩: