Javascript Node.JS和Express res.redirect()未启用新网页
我正在尝试将变量保存到文本文件,但如果在使用spotifyApi.clientCredentialsGrant时找不到该变量,则我希望服务器重定向到app.get'/error',functionreq,res{};显示不同的网页,但返回错误: 节点:11484 UnhandledPromiseRejectionWarning:错误[ERR_HTTP_HEADERS_SENT]:发送到客户端后无法设置头 如何绕过此错误以显示网页error.html 我没有访问EJS或window.location的权限,因为它分别与其他文件冲突,并且是一个node.js程序Javascript Node.JS和Express res.redirect()未启用新网页,javascript,node.js,express,Javascript,Node.js,Express,我正在尝试将变量保存到文本文件,但如果在使用spotifyApi.clientCredentialsGrant时找不到该变量,则我希望服务器重定向到app.get'/error',functionreq,res{};显示不同的网页,但返回错误: 节点:11484 UnhandledPromiseRejectionWarning:错误[ERR_HTTP_HEADERS_SENT]:发送到客户端后无法设置头 如何绕过此错误以显示网页error.html 我没有访问EJS或window.locatio
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '/public', 'homepage.html'));
try {
spotifyApi.clientCredentialsGrant()
.then(function (data) {
// Save the access token so that it's used in future calls
client_cred_access_token = data.body['access_token'];
console.log(client_cred_access_token);
console.log('Client Credentials Success!');
}, function (err) {
console.log('Something went wrong when retrieving an access token', err.message);
throw err;
});
fs.writeFile("./public/client_cred_token.txt", '', function (err) {
console.log('Clearing previous access token');
});
fs.writeFile("./public/client_cred_token.txt", client_cred_access_token, function (err) {
if (err) return console.log(err);
});
fs.readFile('./public/client_cred_token.txt', function (err, data) {
if (err) throw err;
console.log("Saved Client Credentials as: %s", data)
});
}
catch (err) {
res.redirect('/error');
}
});
接受答案的关键是,在确认需要哪个HTML/文件之前,不要向服务器发送任何HTML/文件。
应用程序获取“/”,函数请求,res{
试一试{
spotifyApi.clientCredentialsGrant.Then函数数据{
//保存访问令牌,以便在将来的调用中使用
让客户端访问令牌=data.body['access\u token';
console.logclient_cred_access_令牌;
console.log“客户端凭据成功!”;
//截断令牌文件
fs.truncateSync./public/client_cred_token.txt;
//将令牌写入文件
fs.writeFileSync./public/client\u cred\u token.txt,client\u cred\u access\u token;
//再次从文件中读取令牌
//注意:您可以在此处使用'client\u cred\u access\u token'
让data=fs.readFileSync'/public/client_cred_token.txt';
console.Log已将客户端凭据保存为:%s,数据
//在未引发错误时向客户端发送主页
res.sendFilepath.join_uudirname,“/public”,“homepage.html”;
},函数错误{
日志“检索访问令牌时出错”,err.message;
犯错误;
};
}犯错误{
res.redirect'/错误';
}
}; 您首先调用res.sendFile,然后如果稍后出现错误,您还将调用res.redirect'/error',这意味着您将尝试向一个触发您看到的错误的http请求发送两个响应。你不能那样做
解决方案是在所有其他操作结束时调用res.sendFile,以便在成功时调用它,在出现错误时调用res.redirect,从而只调用其中一个
与这里的另一个答案不同的是,我已经向您展示了如何使用异步文件I/O正确地编写代码,这样设计就可以在真正的服务器中使用,该服务器可以满足多个用户的需求
const fsp = require('fs').promises;
app.get('/', async function (req, res) {
try {
let data = await spotifyApi.clientCredentialsGrant();
// Save the access token so that it's used in future calls
client_cred_access_token = data.body['access_token'];
console.log(client_cred_access_token);
console.log('Client Credentials Success!');
await fsp.writeFile("./public/client_cred_token.txt", client_cred_access_token);
let writtenData = await fsp.readFile('./public/client_cred_token.txt');
console.log("Saved Client Credentials as: %s", writtenData);
res.sendFile(path.join(__dirname, '/public', 'homepage.html'));
} catch (err) {
console.log(err);
res.redirect('/error');
}
});
您首先发送html文件,因此所有的头都被发送,您必须在try块的末尾移动它们。永远不要在服务器的请求处理程序中使用fs函数的同步版本。它会破坏服务器的可伸缩性,因为它会在每次同步fs操作期间阻塞整个事件循环。还有,犯错误;在你拥有它的地方,它将毫无用处。由于您所处的异步回调,try/catch不会捕获它。@jfriend00抛出错误;很好,因为从promise-catch函数可以传递错误。假设在令牌存储逻辑上,OP似乎有超过1个用户它用于学校项目,而不是后勤服务器使用,所以这是正确的。我仍然有一些错误,我可以通过更改catch err来修复,改为只发送error.html,这总体上更干净。马克,非常好,简洁,明智的回答。谢谢:@RhettJarvis-如果我在给基于服务器的学校作业评分,我会因为在请求处理程序中使用同步文件I/O而对其进行评分。这不是任何人应该如何学习编写请求处理程序。