Node.JS和Express res.redirect()未启用新网页



我正试图将一个变量保存到一个文本文件中,但如果在使用spotifyApi.clientCredentialsGrant()时找不到该变量,那么我希望我的服务器重定向到显示不同网页的app.get('/error', function(req, res) {});,但它返回错误:

(节点:11484(未处理的PromiseRetention警告:错误[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置标头

如何绕过此错误来显示网页error.html?

我无法访问EJS或window.location,因为它与其他文件冲突,并且分别是node.js程序。

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.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');
}
});

app.get('/', function (req, res) {
try {
spotifyApi.clientCredentialsGrant().then(function (data) {
// Save the access token so that it's used in future calls
let client_cred_access_token = data.body['access_token'];
console.log(client_cred_access_token);
console.log('Client Credentials Success!');
// truncate token file
fs.truncateSync("./public/client_cred_token.txt");
// write token to file
fs.writeFileSync("./public/client_cred_token.txt", client_cred_access_token);
// read token from file again
// NOTE: you could use `client_cred_access_token` here
let data = fs.readFileSync('./public/client_cred_token.txt');
console.log("Saved Client Credentials as: %s", data)
// send homepage to client when no error is thrown
res.sendFile(path.join(__dirname, '/public', 'homepage.html'));
}, function (err) {
console.log('Something went wrong when retrieving an access token', err.message);
throw err;
});
} catch (err) {
res.redirect('/error');
}
});

我用syncron交换了所有异步文件操作。他们抛出一个错误,你不必处理回调链/流。

此外,我还在try块的botom中移动了sendFile(...),因此当任何syncrhenus函数调用引发错误时,都无法访问sendFile,并且可以将重定向发送到客户端。

否则,您将向客户端发送带有所有标头的homepage.html,并且重定向是不可能的。

最新更新