2014-11-01 41 views
1

我正在使用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.

任何想法?我是新来的蓝鸟,可能是搞砸了一些东西...

回答

-1

为了澄清,正如本杰明在下面指出的,你的问题是你试图在响应对象已经发送客户端。我不确定是否有其他中间件正在返回响应,或者它是否与您在那里的.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(); 
}); 
+0

绝对不是问题,更换.done。 OP的问题并不在于承诺 - 这就是它的说法 - 他将应用程序中的标题发送到应用程序的其他地方,现在尝试再次发送它们(例如,将内容类型设置为JSON)。如果您删除该代码的res/req部分,它就可以工作。 '.done'是古老的承诺库没有检测到未处理的拒绝的遗留物。 – 2014-11-01 23:17:34

+0

我意识到问题在于响应试图发送两次,我认为它可能与完成后的catch有关,所以如果res.json中有错误,catch可能会被触发。我改变了它,所以只有一个响应方法可以被调用。我也在花时间指出他不必使用.done,而且.done后面的.cone并没有真正的意义。这没有意义,是吗? – 2014-11-01 23:26:36

+1

不,但是这可能是他真正的代码,因为'.done'返回'undefined'。 – 2014-11-01 23:34:23

0

你应该.then