在调用第二个从另一个服务器返回一些数据的嵌套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();
}
答案 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