2014-03-24 71 views
0

在調用第二個嵌套的http.request時,nodejs中有一種方法可以修改響應標頭,它可以從另一個服務器返回一些數據? 我總是得到這個錯誤,從下面的功能...在nodejs http.request中更新標頭

catch error: Error: Can't set headers after they are sent. 

從那裏我打電話來檢查令牌是有效的主要功能: req.on(「端」,函數(){
console.log('GET to/api,我有%s的權限嗎?',access_token); validadToken(req,res,next); });

這是爲了驗證對的OAuth2服務器的令牌功能可按,如果響應是401,我試圖獲得新的refresh_token:

function validadToken (req, res, next) { 
     var options = { port: 8080, 
         path: '/api', 
         host: 'localhost', 
         method: 'GET' , 
         headers: {'Authorization': 'Bearer '+ access_token, 
           'Content-Type':'application/x-www-form-urlencoded'} }; 
     req2 = http.request(options, 
      function (response){ 
       response.setEncoding('utf8'); 
       response.on('data', function (chunk) { 
        console.log(".-response=> ", chunk); 
        console.log("statusCode: " + response.statusCode); 

        if(response.statusCode == 401){ 
         console.log(); 
         console.log("===>>>> call to renew/wait for me"); 
         renewToken(response, res, next); 

        }else if(response.statusCode === 200){ 
         console.log("Valid Token... we keep it going!"); 
        } 
        next();    
       }); 
      }); 
     req2.write(formData); 

     req2.end();   
} 

在這裏,我試圖讓刷新令牌,但是當我嘗試更新標題中的新值,我得到上述錯誤。對於refresh_token值是從響應恢復從先前的功能

function renewToken (req, res){ 
    var userUrl = 'grant_type=refresh_token&refresh_token='+refresh_token+'&client_id=XXX&client_secret=XXX'; 
    var optRenew = { port: 8080, 
         path: '/token', 
         host: 'localhost', 
         method: 'POST' , 
         headers: {'Content-Type':'application/x-www-form-urlencoded'} }; 

    renew = http.request(optRenew, 
      function (responseRenew){ 
       console.log("responseRenew"); 
       responseRenew.setEncoding('utf8'); 

       responseRenew.on('data', function (chunk){ 
         console.log(".-responseRenew=> ", chunk); 
         console.log(".-responseRenew=> ", responseRenew.statusCode); 
         accessTokenValue = getToken("access_token", chunk, ',', ':', '"'); 
         refreshTokenValue = getToken("refresh_token", chunk, ',', ':', '"'); 
         console.log("Headers Sent (renew) ? "+ res.headersSent); 
         console.log("¡¡¡New values!!!\n" + accessTokenValue +' '+ refreshTokenValue);  

         res.setHeader("Set-Cookie", ["ninja="+accessTokenValue, "samurai="+refreshTokenValue]); 
         console.log("envio ...."); 
         }) 
      }); 
    renew.write(userUrl); 
    renew.end(); 
} 

回答

0

我想我找到了

if(response.statusCode == 401) { 
    console.log(); 
    console.log("===>>>> call to renew/wait for me"); 
    renewToken(response, res, next); 

} else if(response.statusCode === 200) { 
    console.log("Valid Token... we keep it going!"); 
} 
next(); 

當令牌並不需要更新你打電話next,一切都OK,但是當調用renewToken時,您遇到問題:http.request是異步調用,renewToken在執行處理續訂響應的代碼之前返回,因此在更新的令牌已知之前完成對next的調用。當你調用next時,下一個中間件被調用,這裏很可能下一個中間件會在更新的令牌可用之前發回響應,這就解釋了你的錯誤:在下一個中間件完成響應之後,你嘗試設置響應頭之一

該解決方案實際上是很容易的(我會跳過一些代碼)

function validadToken(req, res, next) { 
    ... 
    req2 = http.request(options, function (response) { 
    response.setEncoding('utf8'); 
    response.on('data', function(chunk) { 
     ... 
     if (response.statusCode == 401) { 
     ... 
     renewToken(req, res, next); 

     } else if (response.statusCode === 200) { 
     console.log("Valid Token... we keep it going!"); 
     next(); 
     } else { 
     // TODO: you should deal with the other cases 
     }     
    }); 
    }); 
    req2.write(formData); 
    req2.end();   
} 

function renewToken(req, res, next) { 
    ... 

    renew = http.request(optRenew, function (responseRenew){ 
    ... 
    responseRenew.on('data', function(chunk){ 
     ...  
     res.setHeader("Set-Cookie", ["ninja="+accessTokenValue, "samurai="+refreshTokenValue]); 
     console.log("envio ...."); 

     // NOW IT'S THE TIME TO CALL THE NEXT MIDDLEWARE 
     next() 
    }) 
    }); 
    renew.write(userUrl); 
    renew.end(); 
} 

TL; DR;你應該只有在得到令牌後才能撥打next

+0

它有效,next()調用始終發送響應。 – Pistolo