[英]SSE - Server Sent Events - How to reuse same EventSource
我是编程新手并试图了解 SSE。 我将 React 用于前端,Node.js 用于后端,MongoDB 用于数据库。 对不起我的英语提前。
当我打开网站时,创建事件源并开始监听后端“/test”。 我在前端有一个按钮,当我点击它时,一个介于 0 和 1 之间的随机浮点数发布了后端“/ savedata”。 还显示大于 0.5 的数字。
在服务器端“/test”,每3秒检查一次数据库是否有新记录,如果记录的数字大于0.5,则将其发送到前端并删除数据库记录。 对于“/savedata”,将数字保存到来自前端的数据库。
我的问题是;
当我在新选项卡中打开网站时,正在创建另一个事件源并触发数据库“/test”。 有没有办法重用事件源而不是创建新的事件源? 另外,如果您对我的代码有任何建议,请告诉我。 我正在尝试学习。
这是我的代码;
前端反应 - FrontendTest.js
import axios from 'axios'
import React, { useEffect, useState } from 'react'
const FrontendTest = () => {
const [data, setData] = useState(null)
const [databaseInfo, setDatabaseInfo] = useState(null)
let number = 0
const url = 'http://localhost:5000/test'
let source
useEffect(() => {
source = new EventSource(url)
source.onmessage = (e) => {
setData(JSON.parse(e.data))
}
}, [])
const buttonClicked = async (e) => {
e.preventDefault()
number = Math.random()
const sendReq = await
axios.post('http://localhost:5000/savedata', {
number,
})
setDatabaseInfo(sendReq.data)
}
return (
<div>
<div>
<button onClick={buttonClicked}>Send</button>
<p>{`If the number > 0.5 , it will be founded`}</p>
<p>
{databaseInfo &&
`${databaseInfo.data.toFixed(4)} Saved to
Database !`}
</p>
<p>
{data && `${data.toFixed(4)} Founded ! Database
input deleted ! `}
</p>
</div>
</div>
)
}
Node.js-server.js
import express from 'express'
import cors from 'cors'
import expressAsyncHandler from 'express-async-handler'
import mongoose from 'mongoose'
import Datas from './model.js'
const app = express()
const port = 5000
app.use(
cors({
origin: 'http://localhost:3000',
credentials: true,
})
)
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
let interval
app.post(
'/savedata',
expressAsyncHandler(async (req, res) => {
const data = req.body.number
const result = await Datas.create({
data1: data,
})
res.send({ data })
})
)
app.get(
'/test',
expressAsyncHandler(async (req, res) => {
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
clearInterval(interval)
interval = setInterval(async () => {
const database = await Datas.find({})
const databaseData1 = database.map((item) => item.data1)
const databaseIds = database.map((item) => item._id)
const data = {
value: databaseData1,
}
for (let i = 0; i < data.value.length; i++) {
if (data.value[i] > 0.5) {
console.log(data.value[i])
res.write(`data: ${JSON.stringify(data.value[i])}\n\n`)
await Datas.findByIdAndDelete(databaseIds[i])
}
}
console.log('Searching')
}, 3000)
})
)
mongoose
.connect(CONNECTION_URL, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() =>
app.listen(port, () =>
console.log(`Example app listening at
http://localhost:${port}`)
)
)
.catch((error) => console.log(error))
您不能直接共享事件源句柄,但您可以做的是在选项卡之间共享数据,当它们位于同一来源时。
一种方法是 LocalStorage。 因此,第一个选项卡将写入将运行 EventSource 连接的存储。 连接的第二个选项卡会看到已经打开了另一个选项卡,然后开始收听。 然后每次事件进入第一个选项卡时,它都会将其写入本地存储,第二个选项卡可以看到它。
(您需要处理如果第一个选项卡关闭时会发生什么情况;尤其是如果有多个其他选项卡在监听,因此请注意,使这个生产就绪会变得相当复杂。)
另一个专门用于做这种事情的 WebAPI 是Broadcast Channel 。 我没用过:浏览器支持和EventSource差不多,但是Safari落后了。
看起来这个问题是为了跟踪各种方法而创建的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.