使用带有nodejs的服务器发送事件并做出反应的问题

Posted

技术标签:

【中文标题】使用带有nodejs的服务器发送事件并做出反应的问题【英文标题】:problem using server sent events with nodejs and react 【发布时间】:2020-05-21 04:00:02 【问题描述】:

我需要将server-sent-events 实现到我的node js 并响应应用程序, 我对此进行了一些研究,并遵循了一些在线教程,尤其是site,因为它很简单。

我的目标是有 1 条路线称为 /api/alert

如果我们使用 JSON 对象向该路由发出 HTTP POST 请求,例如


  "longtitude": 100, 
  "latitude": 35, 
  "userId": "5dc28160e8a69c203002383b"

然后服务器会将它存储在 MongoDB 中,并实时发送给客户端(当然使用服务器发送的事件)

如果我们向该路由发出 HTTP GET 请求,那么它将显示 MongoDB 中的所有当前对象,并且每次有新对象时它都会获取新对象发布。

它就像我想要的那样工作。但是问题来了。 它会实时显示数据库中的对象和新的对象,直到正好 2 分钟后,不知何故连接丢失或发生某些事情使浏览器再次调用 GET /api/alert 然后所有相同的数据已经显示的又显示了。只要我什么都不做,复制就会每 2 分钟发生一次。

我做了很多研究

加载资源失败:net::ERR_INCOMPLETE_CHUNKED_ENCODING

并尝试不同的方法来解决,但它似乎根本没有帮助。

这是一个 nodejs 还是 react 问题。关于我做错了什么或与这个问题有关的任何想法。感谢所有帮助。

这些是我的代码,它基于https://alligator.io/nodejs/server-sent-events-build-realtime-app/ 上的大部分内容:

Nodejs 代码:

const  Fire  = require("../models/fire");

let clients = [];

// Iterate clients list and use write res object method to send new nest
function sendEventsToAll(newFire) 
  clients.forEach(c => 
    c.res.write(`data: $JSON.stringify(newFire)\n\n`);
  );


module.exports.addAlert = async (req, res, next) => 
  const fire = new Fire(req.body);
  res.send(await fire.save());

  return sendEventsToAll(fire);
;

module.exports.handleAlert = async (req, res, next) => 
  const headers = 
    "Content-Type": "text/event-stream",
    Connection: "keep-alive",
    "Cache-Control": "no-cache"
  ;
  res.writeHead(200, headers);
  res.flushHeaders();

  const data = await Fire.find();
  res.write(`data: $JSON.stringify(data)\n\n`);

  // Generate an id based on timestamp and save res
  // object of client connection on clients list
  // Later we'll iterate it and send updates to each client
  const clientId = Date.now();
  const newClient = 
    id: clientId,
    res
  ;
  clients.push(newClient);
  console.log(`$clientId Connection opened`);

  // When client closes connection we update the clients list
  // avoiding the disconnected one
  req.on("close", () => 
    console.log(`$clientId Connection closed`);
    clients = clients.filter(c => c.id !== clientId);
    res.end();
  );
;

反应代码:

import React,  useState, useEffect  from "react";
import "./App.css";

function App() 
  const [nests, setNests] = useState([]);
  const [listening, setListening] = useState(false);

  useEffect(() => 
    if (!listening) 
      const events = new EventSource("http://localhost:3900/api/alert");
      events.onmessage = event => 
        const parsedData = JSON.parse(event.data);

        setNests(nests => nests.concat(parsedData));
      ;

      setListening(true);
    
  , [listening, nests]);

  return (
    <table className="stats-table">
      <thead>
        <tr>
          <th>_id</th>
          <th>longtitude</th>
          <th>latitude</th>
          <th>userId</th>
        </tr>
      </thead>
      <tbody>
        nests.map((nest, i) => (
          <tr key=i>
            <td>nest._id</td>
            <td>nest.longtitude</td>
            <td>nest.latitude</td>
            <td>nest.userId</td>
          </tr>
        ))
      </tbody>
    </table>
  );

export default App;

我遇到的问题的图片

【问题讨论】:

我尝试了其他教程,然后在 2 分钟后我遇到了同样的问题,浏览器的控制台显示该错误并且浏览器再次发出该 HTTP GET。 【参考方案1】:

Nodejs 有 2 分钟的默认超时,这就是您的连接在两分钟后关闭的原因。如果您希望它打开更长的时间,则需要增加默认超时时间。

【讨论】:

以上是关于使用带有nodejs的服务器发送事件并做出反应的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何修复重新启动机器人后无法正常工作的事件

在nodejs,mysql中为上传的图像添加标题并做出反应

插入并放入nodeJs + express api时,带有Redux Saga的Axios不发送表单数据

向每个对 discord.js 中的消息做出反应的用户发送 dm

无法读取未定义的属性“发送”:Discord 机器人创建通道并向其发送消息然后对其做出反应

无法在没有页面重新加载的情况下获取套接字数据,并与下面的代码做出反应