前端41_实时消息实现方式前端轮询后端轮询SSEWebsocketsocket.io
【前端41_实时消息】实现方式:前端轮询、后端轮询(SSE)、Websocket、socket.io
文章目录
目标 + 分析需求
目标是做一个实时聊天的工具
那么我们就要解决问题了啊:如何保证消息实时更新呢?
我们可以不断地发送请求,来实时获取最新数据,从而铺到页面上,这就有几种方法
- 前端轮询
- 建立长链接(前后端一直连接着,有消息更新了,后台就告诉给前台)
- 等等…
我们先根据这几个思路学习些新东西
前端轮询:不推荐
这个就比较低级了,在前端可以写个定时器,里面写请求,前端来不断的发送请求给后端
弊端就很多啦:能把页面给搞垮掉了!!
后端轮询:SSE
简介
全称
server send event
,这个比前端轮询能好一点,主要的工作都交给后端啦,当然也需要前端的配合。
实现思路:后端不断的发送数据给前端,建立长链接
这里选择用 原生 来写
SSE
我们知道,
node
原生的话会有res,write()
,res,end()
,如果要建立长链接的话,就不能结束掉链接,也就是不能res.end()
,然而Koa
中返还的方式是koa-body
,里面是koa
封装的,使用的话会有些问题。
具体操作
后端设置头部,从而建立长链接 ,例如:
res.setHeader("Content-type", "text/event-stream")
开始和结束的标志:
data:
,和
\r\n\r\n
,例如:
res.write('data:时间是' + new Date() + '\r\n\r\n')
前端代码如下:
// html
<script>
const source = new EventSource('/sse');
source.onopen = () => {
console.log('链接成功');
}
source.onmessage = (res) => {
console.log('获得的数据是:' + res.data );
}
source.onerror = (err) => {
console.log(err);
}
</script>
后端代码如下:
// node.js
const http = require('http')
const fs = require('fs')
const server = http.createServer((req, res) => {
const url = req.url;
if (url === '/') {
const data = fs.readFileSync('./index.html')
res.end(data)
} else if (url === '/sse') {
res.setHeader("Content-type", "text/event-stream")
setInterval(() => {
res.write('data:时间是' + new Date() + '\r\n\r\n')
}, 2000);
}
})
server.listen(3000)
SSE 会通过
流
这种形式去传递,可以看一下它的接口形式:
缺点
单工的
,意思就是说只能从一个方向流动,而不能反过来,那这样就有些场景不好了啊,能不能前端,后台双向流通呢?这就引入了
websocket
Websocket
先用原生的写一个哈,
ws
模块需要
npm i
一下,
Node
代码如下:
const WebSocketServer = require('ws').Server
const wss = new WebSocketServer({ port: 5678 })
wss.on('connection', ws => {
setInterval(() => {
let somedata = {
name: '张三',
age: 20
}
ws.send(JSON.stringify(somedata))
}, 2000)
})
前端代码如下:
<script>
var ws = new WebSocket("ws://localhost:5678"); // 建立 webSocket
</script>
没错,简单的 webSocket 连接就这么少~
注意 点:
我们还有方案,结合
Koa
的话,会同时有路由,还有
webSocket
链接
socket.io:Websocket + Koa
后端配置
后端配置服务使用的原生
server
,最后监听的也是
server
,概括如下:
const server = require('http').createServer(app.callback());
const io = require('socket.io')(server);
server.listen(3000);
如果后端想要发送消息的话可以在 io 中的
connection
事件的回调中声明,例子如下:
const server = require('http').createServer(app.callback());
const io = require('socket.io')(server);
io.on('connection', socket => {
let data = '我是想要发送给前端的消息'
socket.emit('clientFn', data) // 广播给一个人
socket.broadcast.emit('clientFn', data) // 广播给除了自己之外的所有人
})
后端监听前端发来的
btnSend
事件:
// node 后端代码:
const server = require('http').createServer(app.callback());
const io = require('socket.io')(server);
io.on('connection', socket => {
socket.on('btnSend', (data) => {
// 逻辑
})
})
前后台建立链接
前端这边,我们需要在页面中引入
socket.io.js
这个文件,可以在 依赖中找到
/node_modules/socket.io-client/dist/socket.io.js
,找到这个文件之后,可以复制出来,然后在页面中引入
<script src="socket.io.js" type="text/javascript"></script>
接着在下面的脚本中建立链接,访问
/
时建立链接
let socket = io.connect("/");
前端配置
前台发送数据:
socket.emit('eventName', data)
前台接收后台的数据:
socket.on('eventName', data => {})
总结
前后端发送和接收的方式非常相似,发送都是
emit(事件名称,数据)
,监听都是
on(事件名称,数据)
,如下图是个例子
踩坑
static 文件夹下的 index.html
如果你在 static 文件夹下 有
index.html
的话,那么当你在浏览器访问根目录的时候就会返回这个
index.html
页面
async await
form 按钮阻止页面刷新
可以在
form
元素上添加如下截图的语句。如果添加这个,那么就不会发送请求。
koa-body
如果不装这个中间件的话,后台的
ctx
中就拿不到前台传来的参数,
ctx.request.body
是没有的,安装完这个中间件后就能拿到了。