无法在已发送后发送标头?

时间:2016-04-07 01:40:33

标签: javascript node.js

对于以下代码,这甚至意味着什么,res.send工作正常,但在我的控制台中,我得到以下消息:

http.js:689
throw new Error('Can\'t set headers after they are sent.');

app.get('/summoner/:summonerName', function(req, res) {
lolapi.Summoner.getByName(req.params.summonerName, function(err, obj) {
  var options = {
    beginIndex: 0,
    endIndex: 1
  };
  lolapi.MatchList.getBySummonerId(obj['savisaar2'].id, options, function(err, matches) {
    var gameMatches = matches.matches;
    for(var i = 0; i < gameMatches.length; i++) {
      lolapi.Match.get(gameMatches[i].matchId, function(err, games) {
        res.send({profile : obj, matchHistory : games});
      });
    }
  });
});
});

1 个答案:

答案 0 :(得分:0)

正如我在评论中所解释的那样,您在res.send()循环内调用for,这意味着您不止一次调用它。每个请求只能调用一次。这就是您在控制台中看到错误消息的原因。

目前尚不清楚你的代码究竟想要做什么,但如果希望将所有结果收集到一个数组中并将它们全部作为响应发送,那么你可以这样做:

app.get('/summoner/:summonerName', function (req, res) {
    lolapi.Summoner.getByName(req.params.summonerName, function (err, obj) {
        if (err) {
            return res.status(500).end();
        }
        var options = {beginIndex: 0, endIndex: 1};
        lolapi.MatchList.getBySummonerId(obj['savisaar2'].id, options, function (err, matches) {
            var gameMatches = matches.matches;
            var results = [];
            for (var i = 0; i < gameMatches.length; i++) {
                lolapi.Match.get(gameMatches[i].matchId, function (err, games) {
                    if (err) {
                        return res.status(500).end();
                    }
                    results.push({profile: obj, matchHistory: games});
                    // if all results are done, then send response
                    if (results.length === gameMatches.length) {
                        res.json(results);
                    }
                });
            }
        });
    });
});

注意:我还添加了基本的错误处理。

如果您希望以您所请求的特定顺序显示结果,那么您可以添加更多代码来执行此操作:

app.get('/summoner/:summonerName', function (req, res) {
    lolapi.Summoner.getByName(req.params.summonerName, function (err, obj) {
        if (err) {
            return res.status(500).end();
        }
        var options = {beginIndex: 0, endIndex: 1};
        lolapi.MatchList.getBySummonerId(obj['savisaar2'].id, options, function (err, matches) {
            var gameMatches = matches.matches;
            var results = new Array(gameMatches.length);
            var cntr = 0;
            for (var i = 0; i < gameMatches.length; i++) {
                (function(index) {
                    lolapi.Match.get(gameMatches[i].matchId, function (err, games) {
                        if (err) {
                            return res.status(500).end();
                        }
                        ++cntr;
                        results[index] = {profile: obj, matchHistory: games};
                        // if all results are done, then send response
                        if (cntr === gameMatches.length) {
                            res.json(results);
                        }
                    });
                })(i);
            }
        });
    });
});

由于Promises现在已成为2016年的标准,所以现在可以了解使用Bluebird promise库的情况:

const Promise = require('bluebird');
Promise.promisifyAll(lolapi.Summoner);
Promise.promisifyAll(lolapi.MatchList);
Promise.promisifyAll(lolapi.Match);

app.get('/summoner/:summonerName', function (req, res) {
    var main;
    lolapi.Summoner.getByNameAsync(req.params.summonerName).then(function(obj) {
        main = obj;
        var options = {beginIndex: 0, endIndex: 1};
        return lolapi.MatchList.getBySummonerIdAsync(obj['savisaar2'].id, options);
    }).then(function(matches) {
        var gameMatches = matches.matches;
        return Promise.map(gameMatches, function(item){
            return lolapi.Match.getAsync(item.matchId).then(function(games) {
                return {profile: main, matchHistory: games};
            });
        });
    }).then(function(results) {
        res.json(results);
    }).catch(function(err) {
        res.status(500).end();
    });
}