Bluebird基于承诺的Express请求处理程序返回错误
问题描述:
我正在使用Express(4.x),Redis(2.8)和Bluebird(2.x) - 需要将多个Redis调用串起来以返回响应:Bluebird基于承诺的Express请求处理程序返回错误
var promise = require('bluebird');
var redis = require('redis');
var redis = redis.createClient(6379,process.env["REDIS_ENDPOINT"],{});
promise.promisifyAll(redis);
// GET
exports.inOffers = function (req, res) {
return redis.smembersAsync('advertisers')
.map(function(advId){
console.log('advId',advId);
return redis.smembersAsync('advertiser:'+advId+':inoffers')
.map(function(inOfferId){
console.log('offerId: ',inOfferId);
return redis.hgetallAsync('advertiser:'+advId+':inoffer:'+inOfferId);
})
})
.done(function(inOffers){
console.log('InOffers: ',inOffers);
res.json({inOffers: inOffers})
})
.catch(function(err){
console.log((new Date).toUTCString()+" [ERROR] ", err);
res.writeHead(500);
res.end();
});
};
根据日志,数据正确地从Redis的聚集,但我得到了下面的错误,而不是响应:
/var/app/current/node_modules/bluebird/js/main/async.js:95 throw res.e; ^Error: Can't set headers after they are sent.
任何想法?我是新来的蓝鸟,可能是搞砸了一些东西...
答
为了澄清,正如本杰明在下面指出的,你的问题是你试图在响应对象已经发送客户端。我不确定是否有其他中间件正在返回响应,或者它是否与您在那里的.done/.catch有关。我会尝试下面的代码来完成承诺链,尽管我不确定它会有帮助。另一个提示 - 每蓝鸟文件,你不需要使用'完成',虽然你可以如果你想(bluebird .done docs)。如果你使用.done,它应该是你的诺言链中的最后一件事(尽管你可以同时拥有完成和拒绝的处理程序,就像.then一样)。
.done(function(inOffers){
console.log('InOffers: ',inOffers);
res.json({inOffers: inOffers})
}, function(err){
console.log((new Date).toUTCString()+" [ERROR] ", err);
res.writeHead(500);
res.end();
});
答
你应该.then
绝对不是问题,更换
.done
。 OP的问题并不在于承诺 - 这就是它的说法 - 他将应用程序中的标题发送到应用程序的其他地方,现在尝试再次发送它们(例如,将内容类型设置为JSON)。如果您删除该代码的res/req部分,它就可以工作。 '.done'是古老的承诺库没有检测到未处理的拒绝的遗留物。 – 2014-11-01 23:17:34我意识到问题在于响应试图发送两次,我认为它可能与完成后的catch有关,所以如果res.json中有错误,catch可能会被触发。我改变了它,所以只有一个响应方法可以被调用。我也在花时间指出他不必使用.done,而且.done后面的.cone并没有真正的意义。这没有意义,是吗? – 2014-11-01 23:26:36
不,但是这可能是他真正的代码,因为'.done'返回'undefined'。 – 2014-11-01 23:34:23