2014-11-01 80 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