簡體   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