MEAN Stack - 发送给客户端后无法设置 headers
MEAN Stack - Cannot set headers after they are sent to client
这让我发疯了..
我正在处理的应用程序抛出 "Cannot set headers after they are sent to the client" 错误。
我对在 back-end 上写任何东西都很陌生,无法弄清楚为什么会抛出这个问题。
我已经通读了所有关于这个问题的相关帖子,但仍然看不出问题出在哪里。
请帮我找到我丢失的东西。
这是我要访问的路由,userRoutes.js:
router.post('/login', (req, res, next) => {
console.log('1');
let fetchedUser;
HaulerUser.findOne({ username: req.body.username })
.then(user => {
console.log('2');
if (!user) {
return res.status(401).json({
message: 'Auth failed'
});
}
console.log('3');
fetchedUser = user;
return bcrypt.compare(req.body.password, user.password);
})
.then(result => {
console.log('4');
if(!result) {
return res.status(401).json({
message: 'Auth failed'
});
}
const token = jwt.sign(
{ username: fetchedUser.username, userId: fetchedUser._id },
'secret_this_should_be_longer',
{ expiresIn: '1hr' }
);
console.log('5');
res.status(200).json({
token: token,
expiresIn: 3600,
userId: fetchedUser._id
});
console.log('6');
})
.catch(err => {
console.log('7');
return res.status(401).json({
message: 'Invalid authentication credentials',
error: err
});
});
});
此外,它只向控制台打印 1、2、4 和 7????
这是主要的 NodeJS 代码。
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization');
res.setHeader(
'Access-Control-Allow-Methods',
'GET, POST, PATCH, PUT, DELETE, OPTIONS'
);
next();
});
app.use('/api/user', userRoutes);
app.use('/api/manifests', manifestsRoutes);
app.use('/api/sites', sitesRoutes);
我对这个有点不知所措......我确定它有点小......请帮忙......
如评论所述,您不止一次调用 res.json()
,这就是错误的意思。
您 运行 遇到了人们在学习如何链接 Promises 时遇到的一个常见问题。返回 res.status(401).json({...})
不会拒绝 Promise,而是 returns res.status(401).json({...})
的结果到下一个 .then()
块,当找不到用户时,该块又在堆栈中执行相同的操作.
您有几个选项可以解决此问题,但最常见的方法是使用异常退出 Promise 链。而不是每个 if
块中的 res.status(401).json({...})
,而是 throw new Error('{an error message}')
。这将退出链并跳转到您的 .catch()
,它发送然后调用 res.status(401).json({...})
。然后,您还可以在将通用消息返回给调用者的同时记录特定的错误消息。
router.post('/login', (req, res, next) => {
console.log('1');
let fetchedUser;
HaulerUser.findOne({ username: req.body.username })
.then(user => {
console.log('2');
if (!user) {
throw new Error(`User '${req.body.username}' not found`);
}
console.log('3');
fetchedUser = user;
return bcrypt.compare(req.body.password, user.password);
})
.then(result => {
console.log('4');
if(!result) {
throw new Error(`Password did not match`);
}
const token = jwt.sign(
{ username: fetchedUser.username, userId: fetchedUser._id },
'secret_this_should_be_longer',
{ expiresIn: '1hr' }
);
console.log('5');
res.status(200).json({
token: token,
expiresIn: 3600,
userId: fetchedUser._id
});
console.log('6');
})
.catch(err => {
console.log('7');
console.log(err);
res.status(401).json({ // You don't need a return here
message: 'Invalid authentication credentials',
error: err
});
});
});
如果您使用的是 Node 8 或更高版本,您可以使用 async
/await
而不是 .then()
/.catch()
,您的代码将按预期运行。
这让我发疯了.. 我正在处理的应用程序抛出 "Cannot set headers after they are sent to the client" 错误。 我对在 back-end 上写任何东西都很陌生,无法弄清楚为什么会抛出这个问题。 我已经通读了所有关于这个问题的相关帖子,但仍然看不出问题出在哪里。 请帮我找到我丢失的东西。
这是我要访问的路由,userRoutes.js:
router.post('/login', (req, res, next) => {
console.log('1');
let fetchedUser;
HaulerUser.findOne({ username: req.body.username })
.then(user => {
console.log('2');
if (!user) {
return res.status(401).json({
message: 'Auth failed'
});
}
console.log('3');
fetchedUser = user;
return bcrypt.compare(req.body.password, user.password);
})
.then(result => {
console.log('4');
if(!result) {
return res.status(401).json({
message: 'Auth failed'
});
}
const token = jwt.sign(
{ username: fetchedUser.username, userId: fetchedUser._id },
'secret_this_should_be_longer',
{ expiresIn: '1hr' }
);
console.log('5');
res.status(200).json({
token: token,
expiresIn: 3600,
userId: fetchedUser._id
});
console.log('6');
})
.catch(err => {
console.log('7');
return res.status(401).json({
message: 'Invalid authentication credentials',
error: err
});
});
});
此外,它只向控制台打印 1、2、4 和 7????
这是主要的 NodeJS 代码。
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization');
res.setHeader(
'Access-Control-Allow-Methods',
'GET, POST, PATCH, PUT, DELETE, OPTIONS'
);
next();
});
app.use('/api/user', userRoutes);
app.use('/api/manifests', manifestsRoutes);
app.use('/api/sites', sitesRoutes);
我对这个有点不知所措......我确定它有点小......请帮忙......
如评论所述,您不止一次调用 res.json()
,这就是错误的意思。
您 运行 遇到了人们在学习如何链接 Promises 时遇到的一个常见问题。返回 res.status(401).json({...})
不会拒绝 Promise,而是 returns res.status(401).json({...})
的结果到下一个 .then()
块,当找不到用户时,该块又在堆栈中执行相同的操作.
您有几个选项可以解决此问题,但最常见的方法是使用异常退出 Promise 链。而不是每个 if
块中的 res.status(401).json({...})
,而是 throw new Error('{an error message}')
。这将退出链并跳转到您的 .catch()
,它发送然后调用 res.status(401).json({...})
。然后,您还可以在将通用消息返回给调用者的同时记录特定的错误消息。
router.post('/login', (req, res, next) => {
console.log('1');
let fetchedUser;
HaulerUser.findOne({ username: req.body.username })
.then(user => {
console.log('2');
if (!user) {
throw new Error(`User '${req.body.username}' not found`);
}
console.log('3');
fetchedUser = user;
return bcrypt.compare(req.body.password, user.password);
})
.then(result => {
console.log('4');
if(!result) {
throw new Error(`Password did not match`);
}
const token = jwt.sign(
{ username: fetchedUser.username, userId: fetchedUser._id },
'secret_this_should_be_longer',
{ expiresIn: '1hr' }
);
console.log('5');
res.status(200).json({
token: token,
expiresIn: 3600,
userId: fetchedUser._id
});
console.log('6');
})
.catch(err => {
console.log('7');
console.log(err);
res.status(401).json({ // You don't need a return here
message: 'Invalid authentication credentials',
error: err
});
});
});
如果您使用的是 Node 8 或更高版本,您可以使用 async
/await
而不是 .then()
/.catch()
,您的代码将按预期运行。