目录

前端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')

https://i-blog.csdnimg.cn/blog_migrate/c2bc143c27fa7f567a6278b26c76bd7f.gif

前端代码如下:

// 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 会通过 这种形式去传递,可以看一下它的接口形式:

https://i-blog.csdnimg.cn/blog_migrate/bec9bc732906f75366ca3af436ef9c4f.gif

缺点

单工的 ,意思就是说只能从一个方向流动,而不能反过来,那这样就有些场景不好了啊,能不能前端,后台双向流通呢?这就引入了 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 连接就这么少~

注意 点:

https://i-blog.csdnimg.cn/blog_migrate/04afb272dde1d8c29a5747e33e9d3ce3.png

我们还有方案,结合 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(事件名称,数据) ,如下图是个例子

https://i-blog.csdnimg.cn/blog_migrate/8ff701faf97909a06d92ed459ae50bf9.png


踩坑

static 文件夹下的 index.html

如果你在 static 文件夹下 有 index.html 的话,那么当你在浏览器访问根目录的时候就会返回这个 index.html 页面 https://i-blog.csdnimg.cn/blog_migrate/1f8153ad1f8aa178801f764c7fea53b8.gif

async await

https://i-blog.csdnimg.cn/blog_migrate/50b5cebd9109238096c144751bc98782.png

form 按钮阻止页面刷新

可以在 form 元素上添加如下截图的语句。如果添加这个,那么就不会发送请求。

https://i-blog.csdnimg.cn/blog_migrate/c9f7a592c09c4714e77cc6dd119bb1c6.png

koa-body

如果不装这个中间件的话,后台的 ctx 中就拿不到前台传来的参数, ctx.request.body 是没有的,安装完这个中间件后就能拿到了。

https://i-blog.csdnimg.cn/blog_migrate/ecaed11ec330efa826de5b2928eaca2e.png