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

时间:2015-04-04 12:36:07

标签: node.js asynchronous architecture external executable

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

  • 运行Web GUI(简单的HTML / JS)
  • 根据用户输入运行外部程序(二进制文件)

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

enter image description here

  1. 用户输入参数并按下操作按钮。
  2. 服务器使用来自用户的params运行外部程序。
  3. 当程序返回时,Server获取输出(XML文件)并放入 DB中的内容。
  4. Server然后使用DB的结果更新客户端。
  5. 应该注意,用户可以使用不同的参数同时运行多个外部程序。

    外部程序完成后,我应该如何更新客户端(Web GUI):是否必须是客户端轮询更新(例如,如果结果在此处,请查看数据库) ?或者有没有办法从服务器“推送”到客户端?

    我也在考虑设计示例来实现这一目标,因此请随时提供有关此架构的建议和资源。

3 个答案:

答案 0 :(得分:2)

我开始在我的应用程序中使用队列,我遇到了和你一样的问题。

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

我认为这叫做Pub / Sub。有一些技术如Redis也可以帮助实现它。

我也想收到有关这种方法的反馈意见。你觉得怎么样?

答案 1 :(得分:2)

你肯定想使用Socket.io,正如Tulio建议的那样。您特别要求了解如何更新客户端的想法,因此我将假设您知道在服务器执行外部程序时您将如何知道。< / p>

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);

要确保套接字安全,您需要保护您的网址...例如HTTPS也可以保证您的套接字安全。

答案 2 :(得分:1)

好的,似乎您需要两种类型的更新。

1)外部程序完成执行时

...你需要告诉快递服务器发生了什么以及结果。这里最简单的方法是在已经拥有的快速公共(或私有)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
        }
    );
}

如果这些服务器不在同一台计算机上,您还需要快速服务器中的相应/api/task/:id/路由和一些安全性。

2)当快递服务器发现任务已完成时

...您需要通知当前活跃的用户。在这种情况下,这将发生在/api/task/:id/请求处理程序中。从此处通知用户浏览器的最佳方式是socket.io。它非常容易在节点中安装,并将处理所有遗留的浏览器问题。

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

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);
});