外部程序返回后Nodejs如何更新客户端?

Nodejs how to update client after external program has returned?

我正在编写一个主要做两件事的 NodeJS 应用程序:

我希望能够异步地 运行 这些外部程序,因为它们可能需要几分钟才能完成。当他们 return 时,我想更新 Web GUI 以显示结果。这是最基本的概念:

  1. 用户输入参数并按下操作按钮。
  2. 服务器运行是带有用户参数的外部程序。
  3. 当程序 returns 时,服务器获取输出(XML 文件)并放入 数据库中的内容。
  4. 服务器随后使用来自数据库的结果更新客户端。

需要注意的是,用户可以同时运行多个外部程序,参数不同。

当外部程序完成时,我应该如何更新客户端(Web GUI):是否必须由客户端轮询更新(例如,通过查看数据库是否结果在这里)?或者有没有办法 "push" 从服务器到客户端?

我也在查看设计示例以实现此目的,因此请随时提供有关此体系结构的建议和资源。

我开始在我的应用程序中使用队列,我和你有同样的问题。

我认为(但仍未尝试)的一个解决方案是在用户启动此类异步进程时启动套接字(使用 socket.io)并发送回调 url(指向您的快递服务器)到流程。 回调将有一个 client/session id 参数来标识发出请求的人并选择正确的套接字将消息推回。 使用套接字,您不必从客户端到服务器进行池化。

我觉得这叫Pub/Sub。 Redis 等一些技术也可以帮助实现它。

我也想收到有关此方法的反馈。你怎么看?

好的,看来您需要两种类型的更新。

1) 当外部程序执行完毕

...你需要告诉快递服务器发生了什么以及结果。这里最简单的方法是简单地在 express 的 public(或私有)API 上点击一个方法,它已经有了。

例如,使用 request library:

var request = require('request');

var EXPRESS_URL = 'http://localhost:8080/api/task'

//...

// This is called after you save results to database
function onTaskCompleted(taskId, result) {
    request.put(
        {
            url: EXPRESS_URL + '/' + taskId,
            json: result
        },
        function (err, httpResponse, body) {
            // Handle response
        }
    );
}

如果这些服务器不在同一台机器上,您还需要在您的 express 服务器中有相应的 /api/task/:id/ 路由和一些安全措施。

2) 当 express server 发现一个任务已经完成时

...您需要通知当前活跃的用户。在这种情况下,这将发生在 /api/task/:id/ 请求处理程序中。从这里通知用户浏览器的最佳方式是通过 socket.io。在 node 中安装真的很容易,并且会解决所有遗留浏览器问题。

在服务器上,你可以这样使用它:

app.put('/api/task/:id', function (req, res) {
    var payload = {
        id: req.params.id,
        result: req.data
    };
    io.emit('task_completed', payload);
});

在客户端:

io.on('task_completed', function (data) {
    alert('Task ' + data.id + ' has finished with result ' + data.result);
});

您肯定想使用 Socket.io,正如 Tulio 所建议的。您特别询问了如何更新客户端的想法,所以我假设您知道如何知道服务器何时执行完外部程序。

websocket 允许您的服务器随时将数据发送回客户端,例如当您的程序完成时。它消除了您使用长轮询或 ajax 技术的需要,这些技术可能会比您希望的占用更多的开发周期。

Socket.io 是 最好、最受欢迎的 websocket 包装器之一。它是跨浏览器的,甚至移动支持也是无与伦比的。基本上,如果你是 运行 一个 node.js 服务器,你想使用 socket.io。

这是我昨晚推荐给一位同事的很棒的教程:

https://nodesource.com/blog/understanding-socketio

而且,为了节省您大量的搜索时间,我想我还要提到创建跨文件客户端套接字。您只需在主 html 文件中声明套接字变量:

index.html:

<html>
<script src="https://cdn.socket.io/socket.io-1.3.4.js"></script>
<script>
    var socket;
    var connected=false;
</script>
</html>

main.js:

socket = io.connect('http//localhost'); //Make sure you include http//

socket.on('connect'){

    connected = true;
});

secondary.js:

setInterval(function(){

     if(connected === true){

          socket.emit('doesThisWork', true);
     };

}, 100);

此外,要强制建立新连接,您可以:

socket = io.connect('http//localhost', {'force new connection': true);

为了确保套接字安全,您需要保护您的 url... 例如HTTPS 也能确保您的套接字安全。