在web端,很多时候我们需要服务器主动向浏览器发消息,比如实现一个事实聊天窗口,比如实现一个地图,然后实时显示路径拥挤程度,实现一个实时变化的数据大屏,如果使用普通的http请求,那么我们就得写一个定时器,然后定时向对应的接口发起请求,服务器返回相关的数据,这种方式叫做轮询。
轮询是指由浏览器每隔一段时间(如每秒)向服务器发出HTTP请求,然后服务器返回最新的数据给客户端。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求与回复可能会包含较长的头部,其中真正有效的数据可能只是很小的一部分,所以这样会消耗很多带宽资源。
轮询不仅会消耗很多带宽资源,同时因为每次请求都要经历3次握手和4次挥手,所以延迟也是比较高的,并且你无法实时的获取到数据,因为你不知道服务器上的数据什么时候会刷新,同时因为请求次数的增多,所以对服务器的压力也很大。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
1. 实现
如果需要使用WebSocket,那么首先你的服务器需要支持WebSocket,而这里就拿Nodejs来举例,Nodejs有一个名字叫做socket.io
的框架,使用它,可以让你很轻易的就可以创建一个支持WebSocket的服务器。而且该框架使用的人数非常多:
2. 开始使用
使用的方式也非常的简单,我们这里通过React来做前端框架,后端用Nodejs来书写。
2.1 服务端安装
首先是服务器端,一般来讲,使用Nodejs做服务器,那么就会用到一个服务器框架,叫做express,该框架大大简化了使用Nodejs搭建一个服务器的难度,当然,如果是一个比较庞大的项目,目前来讲推荐使用Nestjs,这里我们就仅仅只讲express。
新建一个文件夹,进入到文件中,初始化Node项目:
# 这里的-y代表全部选择默认值
npm init -y
然后引入包:
# 使用npm或者yarn
npm i express socket.io
yarn add express socket.io
创建代码:
const app = require("express")();
const http = require("http").Server(app);
// cors: true 代表接受跨域
const io = require("socket.io")(http, { cors: true });
// socket代表客户端对象,可以通过它向客户端发送一些消息
io.on("connection", (socket) => {
// 一旦客户端连接成功,就会触发下面的语句
console.log("连接成功");
});
http.listen(8000, () => {
console.log("监听端口:8000");
});
其中cors: true
代表可以跨域访问,因为现在前后端分离的关系,所以肯定会涉及到跨域,所以我们需要处理一下跨域。
到这里,一个简单的支持WebSocket的服务器就已经创建好了,是不是非常简单。
2.2 客户端安装
对于客户端,也就是前端项目,我们需要引入socket.io-client
这个包:
# 使用npm或者yarn
npm i socket.io-client
yarn add socket.io-client
该包的使用也非常的简单,
import { io } from "socket.io-client";
// 连接一个WebSocket服务器
const socket = io("ws://localhost:8000");
注意:服务器的前缀一定要为ws://
不能为http://
或者https://
,端口号一定要对应服务器设置的端口号。
这样就连接到了WebSocket服务器。
同时在服务器的控制台中,应该可以看到输出了连接成功的字样:
3. 方法
socket.io有两个非常重要的方法,一个是socket.on
,一个是socket.emit
。
- socket.on:注册一个事件。
- socket.emit:触发一个事件。
这两个方法在客户端和服务器都是会用到的,比如服务端使用socket.on注册一个登陆事件。
io.on("connection", (socket) => {
console.log("连接成功");
// 注册一个登陆事件
// data为前端传来的数据
socket.on("signIn", data => {
// 打印data
console.log(data);
// ...后面可以写登陆相关的逻辑
});
});
注意:因为socket表示客户端对象,所以事件应该注册到该客户端对象上,客户端才能进行触发该事件。
客户端触发事件的方法:
// 连接一个WebSocket服务器
const socket = io("ws://localhost:8000");
const data = {
name: "张三",
age: 80,
};
// 触发登陆事件,并且将data传递给服务器。
socket.emit("signIn", data);
这个时候可以看到控制台中打印了相关的数据:
同理,服务端往客户端传递数据也使用同样的方法:
客户端只需要注册相应的事件:
socket.on("success", data=>{
console.log(data)
})
服务器触发相关事件
io.on("connection", (socket) => {
console.log("连接成功");
// 注册一个登陆事件
// data为前端传来的数据
socket.on("signIn", (data) => {
// 打印data
console.log(data);
// 触发登陆成功的逻辑,并且将data返回给客户端
socket.emit("success", data);
});
});
可以看到,客户端也输出了相应的数据:
而服务器如果需要向所有的客户端都发送消息,则值需要使用io.emit("success", data)
,那么每个客户端都会接收到相同的消息。
4. 最后
socket.io
这个框架大大的简化了WebSocket的实现和操作难度,所以截止目前为止,socket.io
在GitHub上已经有50K+star,相对来说也是一个非常值得信赖的库,更新的也比较频繁,社区也比较活跃,本篇文章仅仅介绍了该库的最基本的用法,如果有更多的需求还是建议去读一下官方文档,我大致看了一下,官方文档写的还是非常详细的。