Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 每次在NodeJs中命中api端点时发送服务器发送事件(SSE)_Node.js_Server Sent Events - Fatal编程技术网

Node.js 每次在NodeJs中命中api端点时发送服务器发送事件(SSE)

Node.js 每次在NodeJs中命中api端点时发送服务器发送事件(SSE),node.js,server-sent-events,Node.js,Server Sent Events,我正在尝试实现一种方法,在每次命中服务器的端点时,在NodeJs中发送服务器发送事件(SSE) 我是如何做到这一点的 //...code... import EventSource from "eventsource"; const EventEmitter = require('events'); const events = new EventEmitter(); // events.setMaxListeners(10); // api end point route from wh

我正在尝试实现一种方法,在每次命中服务器的端点时,在NodeJs中发送服务器发送事件(SSE)

我是如何做到这一点的

//...code...
import EventSource from "eventsource";

const EventEmitter = require('events');
const events = new EventEmitter();
// events.setMaxListeners(10);


// api end point route from where the new order requests will be coming
router.route('/new-order')
  .post((req, res) => {
    const orderData = req.body.data;
    //... save order and emit an event to send response to the client react app
    events.emit('newOrder', orderData);
  });

// define a function to send SSE events to the client
const sse = res => data => {
  const dataToSend = JSON.stringify(data);
  res.write(`data:${dataToSend}`);
  res.write("\n\n");
};

// define an EventSource route for the client to be connected for new events
router.route('/sse')
  .get((req, res) => {

    res.writeHead(200, {
      "Connection": "keep-alive",
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
    });

    res.write("\n");

    const sendSSE = sse(res);
    /*
    PROBLEMATIC CODE-- EACH request to /sse route adds new event listener,
    and in minutes, it exceeds the limit of maxListeners, and I get the warning 
    to increase the max event listeners limit by using setMaxListeners()
    even if only 1 user is using the front end app.
    */
    events.on('newOrder', sendSSE);
  });

//...Code...


// Client Side
const newOrderReceived = (e) => {
  console.log(JSON.parse(e.data));
};

if ( !window.eventSource ) {
  window.eventSource = new EventSource('https://example.com/sse');
  window.eventSource.onmessage = newOrderReceived;
}
但问题是,即使只有一个用户在使用该应用程序,maxListeners也会以非常快的速度耗尽

如果我将事件绑定代码更改为

events.once('newOrder', sendSSE);
events maxListeners错误消失,但在第一次订购后不会通知我的应用程序。 我无法找到将事件绑定到我的
/sse
路由之外的方法,因为我需要通过

res.write(`data:${dataToSend}`);
res.write("\n\n");
在我的例子中,
res
对象仅在路由内部可用

这个问题的解决方案是什么,或者是否有更好的方法可以在NodeJS中发送server sent event(SSE),以便在每次收到API端点上的请求时通知我的前端应用程序

任何帮助都将不胜感激


p.S:我在搜索此问题时看到的所有教程/指南都在发送数据的路由中实现了设置间隔,我没有找到解释如何发送数据以响应服务器上的事件的教程。

以下是我解决此问题的方法

// Events.js File
const EventEmitter = require('events');
const events = new EventEmitter();
events.setMaxListeners(parseInt(config.MAX_EVENT_LISTENERS));

events.on('error', (err) => {
  // handle Error
});

// event to fire on each new order.
events.on('newOrder', (data) => {
  // and in the events.js file, I access it from the global scope of Node
  // so this is the `res` object from the route where I want to send SSE.
  if ( global.sseResponse ) {
    const sendSSE = sse(global.sseResponse);
    sendSSE(data);
  } else {
    // no sse listener, do something else,
  }
});

module.exports = events;
在我的路由文件中

// My routes file where I want to use this
router.route('/sse')
  .get(
    (req, res) => {

      res.writeHead(200, {
        "Connection": "keep-alive",
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
      });

      res.write("\n");
      // Node has a global variable as browsers have a window variable, I attached the res object of my route to
      // the Node's global object to access it outside of this route
      global.sseResponse = res;
      const sendSSE = ApiController.sse(res);
      // keep the connection on
      setInterval(() => {
        sendSSE({ message: 'keep-connection-alive' });
      }, 5000);
    });
这是我用来发送sse的函数,你可以把它写在任何你想写的地方,然后把它导出到多个地方

// function to send server sent events (sse)
const sse = res => data => {
  const dataToSend = JSON.stringify(data);

  res.write(`data:${dataToSend}`);
  res.write("\n\n");

  // this is the important part if using the compression npm module
  res.flush();
},

使用这种方法解决了我的问题,希望它也能帮助其他人。

以下是我如何解决这个问题的

// Events.js File
const EventEmitter = require('events');
const events = new EventEmitter();
events.setMaxListeners(parseInt(config.MAX_EVENT_LISTENERS));

events.on('error', (err) => {
  // handle Error
});

// event to fire on each new order.
events.on('newOrder', (data) => {
  // and in the events.js file, I access it from the global scope of Node
  // so this is the `res` object from the route where I want to send SSE.
  if ( global.sseResponse ) {
    const sendSSE = sse(global.sseResponse);
    sendSSE(data);
  } else {
    // no sse listener, do something else,
  }
});

module.exports = events;
在我的路由文件中

// My routes file where I want to use this
router.route('/sse')
  .get(
    (req, res) => {

      res.writeHead(200, {
        "Connection": "keep-alive",
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
      });

      res.write("\n");
      // Node has a global variable as browsers have a window variable, I attached the res object of my route to
      // the Node's global object to access it outside of this route
      global.sseResponse = res;
      const sendSSE = ApiController.sse(res);
      // keep the connection on
      setInterval(() => {
        sendSSE({ message: 'keep-connection-alive' });
      }, 5000);
    });
这是我用来发送sse的函数,你可以把它写在任何你想写的地方,然后把它导出到多个地方

// function to send server sent events (sse)
const sse = res => data => {
  const dataToSend = JSON.stringify(data);

  res.write(`data:${dataToSend}`);
  res.write("\n\n");

  // this is the important part if using the compression npm module
  res.flush();
},

使用这种方法解决了我的问题,希望它也能帮助其他人。

我现在正面临着同样的问题。您找到访问
res
对象的方法了吗?@fsociety我已经添加了解决此问题的解决方案,您可以查看下面的答案。谢谢。我现在正面临着同样的问题。您找到访问
res
对象的方法了吗?@fsociety我已经添加了解决此问题的解决方案,您可以查看下面的答案。非常感谢。