更新nodejs http.request中的标头

时间:2014-03-24 17:13:35

标签: node.js oauth

在调用第二个从另一个服务器返回一些数据的嵌套http.request时,nodejs有一种修改响应头的方法吗? 我总是从下面的函数中得到这个错误...

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

我打电话来检查令牌是否有效的主要功能:      req.on(' end',function(){
            console.log(' GET到/ 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();  
}

1 个答案:

答案 0 :(得分: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即可,但是当调用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