[英]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.