简体   繁体   English

使用服务器发送的事件:如何存储与客户端的连接?

[英]Using server-sent events : how to store a connection to a client?

I there,在这里,

I have setup a SSE connection between a react-native app and a NodeJS server.我已经在 react-native 应用程序和 NodeJS 服务器之间建立了 SSE 连接。 I followed some guidelines to set it up in client side, polyfilling EventSource and all, this is pretty straight forward.我按照一些指南在客户端设置它,填充EventSource等等,这非常简单。 But on the server side, I have some issue finding out how to store the connection with the client.但是在服务器端,我在找出如何存储与客户端的连接时遇到了一些问题。 I chose store the Response in a global object, but I have the feeling this is not the proper way to do.我选择将响应存储在global object 中,但我觉得这不是正确的做法。 Can somebody advise?有人可以建议吗?

Here is my code below这是我下面的代码


const SSE_RESPONSE_HEADER = {
  'Connection': 'keep-alive',
  'Content-Type': 'text/event-stream',
  'Cache-Control': 'no-cache',
  'X-Accel-Buffering': 'no'
};

const getUserId = (req, from) => {
  try {
    // console.log(from, req.body, req.params)
    if (!req) return null;
    if (Boolean(req.body) && req.body.userId) return req.body.userId;
    if (Boolean(req.params) && req.params.userId) return req.params.userId;
    return null
  } catch (e) {
    console.log('getUserId error', e)
    return null;
  }
}

global.usersStreams = {}

exports.setupStream = (req, res, next) => {

  let userId = getUserId(req);
  if (!userId) {
    next({ message: 'stream.no-user' })
    return;
  }

  // Stores this connection
  global.usersStreams[userId] = {
    res,
    lastInteraction: null,
  }

  // Writes response header.
  res.writeHead(200, SSE_RESPONSE_HEADER);

  // Note: Heatbeat for avoidance of client's request timeout of first time (30 sec)
  const heartbeat = {type: 'heartbeat'}
  res.write(`data: ${JSON.stringify(heartbeat)}\n\n`);
  global.usersStreams[userId].lastInteraction = Date.now()

  // Interval loop
  const maxInterval = 55000;
  const interval = 3000;
  let intervalId = setInterval(function() {
    if (!global.usersStreams[userId]) return;
    if (Date.now() - global.usersStreams[userId].lastInteraction < maxInterval) return;
    res.write(`data: ${JSON.stringify(heartbeat)}\n\n`);
    global.usersStreams[userId].lastInteraction = Date.now()
  }, interval);


  req.on("close", function() {
    let userId = getUserId(req, 'setupStream on close');
    // Breaks the interval loop on client disconnected
    clearInterval(intervalId);
    // Remove from connections
    delete global.usersStreams[userId];
  });

  req.on("end", function() {
    let userId = getUserId(req, 'setupStream on end');
    clearInterval(intervalId);
    delete global.usersStreams[userId];
  });

};

exports.sendStream = async (userId, data) => {
  if (!userId) return;
  if (!global.usersStreams[userId]) return;
  if (!data) return;

  const { res } = global.usersStreams[userId];

  res.write(`data: ${JSON.stringify({ type: 'event', data })}\n\n`);
  global.usersStreams[userId].lastInteraction = Date.now();

};

My first tip is to simply get rid of global ;我的第一个提示是简单地摆脱global it's ok to have a variable in your module's closure.在模块的闭包中有一个变量是可以的。 Your module can encapsulate this "global" state without making it globally accessible to all other modules.您的模块可以封装这个“全局”state,而不需要所有其他模块全局访问它。

const usersStreams = {};

Second, it's probably not impossible for the same user to have multiple connections established.其次,同一个用户建立多个连接可能并非不可能。 I'd recommend that if you're keying these connections on userId , you ought to have the values in userStreams for these keys as collections so you can write to multiple.我建议,如果您在userId上键入这些连接,则应该将这些键的userStreams中的值设置为 collections 以便您可以写入多个。 Either that or you'd need a more unique key.要么,要么你需要一个更独特的密钥。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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