节点 - 在循环结束时向浏览器发送响应

时间:2017-01-19 10:46:51

标签: javascript node.js asynchronous

我正在其中一条路线POST中发出add-users请求。我创建了一个名为success的数组。在每个循环中,如果API POST成功运行,我将向字符串添加字符串'user added'。一旦数组完成,我想用成功数组将响应发送到浏览器。

我注意到一些奇怪的事情。当我输入网址add-users的开头时,它会在我按Enter键导航到页面之前运行循环。这看起来很奇怪?节点是否正在监听并预测我将要访问哪个URL?

这是我目前的尝试,但由于某种原因它不起作用。

app.get('/add-users', function (req, res) {
    var success = [];
    var count = 0;

    users.forEach(function(user, i){

        request({
            url: url,
            method: 'POST',
            json: true
        }, function(err, resp, body){
            if (!err && resp.statusCode === 200) {
               success.push('user added'); 
            }
        });

        if(count === users.length) {
          res.json(success);
        }
    });
});

3 个答案:

答案 0 :(得分:1)

这里的问题是你以错误的方式将同步和异步代码混合在一起。请注意forEach is synchrounous和请求是异步的。因此,循环用户的结束速度比从请求方法获得的第一个结果更快。

答案 1 :(得分:0)

关于浏览器在点击url上的输入键之前获取响应,这是非常不寻常的行为。也许你应该检查你的机器是否被任何恶意软件感染了!

关于您使用的代码,forEach不会在users.length循环中的任何位置递增。所以它永远是0,永远不会等于count。所以循环将结束但它永远不会发送响应。

此外,您正在测试代码中错误位置的users.lengthapp.get('/add-users', function (req, res) { var success = []; var count = 0; users.forEach(function(user){ request({ url: url, method: 'POST', json: true }, function(err, resp, body){ if (!err && resp.statusCode === 200) { success.push('user added'); } count++; // <<=== increment count // if(count === users.length) { // and then test if all done res.json(success); } }); }); }); 之间的相等性。

此代码应该有效:

server {
    # ... here goes your proxy configuration

    # Avoid 504 HTTP Timeout Errors
    proxy_connect_timeout       605;
    proxy_send_timeout          605;
    proxy_read_timeout          605;
    send_timeout                605;
    keepalive_timeout           605;
}

答案 2 :(得分:0)

@SantanuBiswas有一种方法可以解决您的问题,在请求完成之前返回响应,但取决于您在阵列中有多少用户以及上游服务有多慢,这可能是灾难性的用户体验,因为它将等待所有请求完成,然后才会回复响应。

更好的解决方案(在我看来)将立即使用202 Accepted状态代码进行响应,然后使用有关每个用户在请求处理程序中的状态的信息更新您的数据库,以便以后进行报告或调试。这样的事情(假设您正在为本地用户存储使用mongoose):

app.get('/add-users', function (req, res) {
   res.setStatus(202).send(); // you can put more info in the body if desired

users.forEach(function(user){

    request({
        url: url,
        method: 'POST',
        json: true
    }, function(err, resp, body){
        const status = err ? 'error' : 'complete';  // obviously you might want to put more info somewhere, eg. error log, if there is an error
        User.update({_id: user.id}, {status:status}, function(e) { if (e) console.error(err);});
    });
});

});

另一种方式,虽然它增加了解决方案的复杂性,但是每次request完成时都要实施websockets以使客户端更新。这个例子比我在这里发布的时间要长一点,但我链接的网站上的文档非常好。