繁体   English   中英

SSE - 服务器发送事件 - 如何重用相同的 EventSource

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM