【问题标题】:NodeJS - Response streamNodeJS - 响应流
【发布时间】:2018-01-21 13:14:35
【问题描述】:

我使用 Sails.js 使用 NodeJS 构建了一个简单的 API 端点。

当有人访问我的 API 端点时,服务器开始等待数据,每当出现新数据时,他使用套接字广播它。每个客户端都应根据其用户输入接收自己的数据流。

var Cap = require('cap').Cap;

collect: function (req, res) {

var iface = req.param("ip");

var c = new Cap(),
device = Cap.findDevice(ip);

    c.on('data', function(myData) {
        sails.sockets.blast('message', {"host": myData});
    });
});

响应未完成(我从不发送 res.json() - 实际发生的是浏览器继续加载 - 但上述功能有效)。

2 个问题:

  • 我正在尝试从我的客户端订阅和取消订阅此 API 端点(使用 RxJS)。当我订阅时,我开始通过套接字接收数据 - 但我无法取消订阅 API 端点(浏览器希望请求完成)。

  • 每个客户端都应该根据请求 IP 参数订阅自己的套接字房间(参见更新的代码)。目前它向所有人发送消息。

如何使用 Sails.js 创建一个类似于流/服务的 API 端点,该端点将根据每个用户的输入向他发送新数据?

我的目标是能够从每个客户端订阅/取消订阅此 API 端点。

【问题讨论】:

    标签: node.js sockets sails.js rxjs


    【解决方案1】:

    修改后的答案

    假设您的 API 端点在 config/routes.js 中定义如下:

    ...
    'get     /collect': 'SomeController.collectSubscribe',
    'delete  /collect': 'SomeController.collectUnsubscribe',
    

    由于每个Cap 实例都绑定到一台设备,因此我们需要为每个订阅提供一个实例。我们没有使用join/leave 方法,而是在内存中跟踪Cap 实例,并且只跟踪broadcast 到请求套接字的ID。这是因为 Sails 套接字默认订阅了它们自己的 id。

    api/controllers/SomeController.js:

    // In order for the `Cap` instances to persist after `collectSubscribe` finishes, we store them all in an Object, associated with which socket the were created for.
    var caps = {/* req.socket.id: <instance of Cap>, */};
    
    module.exports = {
    
    ...
    
      collectSubscribe: function(req, res) {
        if (!res.isSocket) return res.badRequest("I need a websocket! Help!");
        if (!!caps[req.socket.id]) return res.badRequest("Dude, you are already subscribed.");
    
        caps[req.socket.id] = new Cap();
        var c = caps[req.socket.id]; // remember that `c` is a reference to our new `Cap`, not a copy.
        var device = c.findDevice(req.param('ip'));
    
        c.open(device, ...);
        c.on('data', function(myData) {
          sails.sockets.broadcast(req.socket.id, 'message', {host: myData});
        });
    
        return res.ok();
      },
    
      collectUnsubscribe: function(req, res) {
        if (!res.isSocket) return res.badRequest("I need a websocket! Help!");
        if (!caps[req.socket.id]) return res.badRequest("I can't unsubscribe you unless you actually subscribe first.");
    
        caps[req.socket.id].removeAllListeners('data');
        delete caps[req.socket.id]; 
    
        return res.ok();
      }
    }
    

    基本上是这样的:当浏览器请求触发collectSubscribe时,一个新的Cap实例会监听提供的IP。当浏览器触发collectUnsubscribe时,服务器会检索Cap实例,告诉它停止监听,然后将其删除。

    生产注意事项:请注意Caps 的列表不是持久的(因为它存储在内存中而不是数据库中)!因此,如果您的服务器关闭并重新启动(由于闪电风暴等),该列表将被清除,但考虑到所有 websocket 连接无论如何都会被丢弃,我认为没有必要担心这一点。

    旧答案,留作参考

    您可以使用sails.sockets.join(req, room)sails.sockets.leave(req, room) 来管理socket room。本质上,您有一个名为“collect”的房间,只有加入该房间的套接字才会收到sails.sockets.broadcast(room, eventName, data)

    更多关于如何使用sails.socketshere的信息。

    api/controllers/SomeController.js:

    collectSubscribe: function(req, res) {
      if (!res.isSocket) return res.badRequest();
    
      sails.sockets.join(req, 'collect');
      return res.ok();
    
    },
    
    collectUnsubscribe: function(req, res) {
      if (!res.isSocket) return res.badRequest();
    
      sails.sockets.leave(req, 'collect');
      return res.ok();
    }
    

    最后,我们需要告诉服务器将消息广播到我们的'collect' 房间。 请注意,这只需要发生一次,因此您可以在config/ 目录下的文件中执行此操作。

    对于这个例子,我会把它放在config/sockets.js

    module.exports = {
      // ...
    };
    
    
    c.on('data', function(myData) {
      var eventName = 'message';
      var data = {host: myData};
      sails.sockets.broadcast('collect', eventName, data);
    });
    

    我假设c 可以在这里访问;如果没有,您可以将其定义为 sails.c = ... 以使其全局可访问。

    【讨论】:

    • 首先,感谢您的精彩回答!我有一个问题:目前我必须使用从请求(req.param("ip")) 得到的参数初始化c,并且每个用户都需要在自己的房间里。 c.on('data') 根据用户输入发出新数据
    • 好的,哇,这与我想象的最终目标不同!如果您可以使用某些特定细节来编辑您的问题,那将有很大帮助。另外,我想看看c 是如何声明的,因为它现在似乎与问题更相关。谢谢!
    • 对不起,我是在看到你的回答后才想到的。我相应地更新了我的问题
    猜你喜欢
    • 2019-07-12
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-29
    相关资源
    最近更新 更多