如何解决NodeJs:发送到客户端后无法设置标头
我正在使用验证 jwt 令牌在路由中创建一个简单的有效登录检查
在路线中:
router.post("/contacts",async function (req,res,next) {
await checkLogin(req,next);
res.send(userController.getContacts());
});
async function checkLogin(req,next) {
const loggedIn = await userController.isLoggedIn(req);
if (!loggedIn) {
res.status(401).json({ error: "You are not authorized" });
}
}
在控制器中
async function isLoggedIn(req) {
let token = req.header("authorization");
if (!token) {
return false;
}
token = token.substring(7); //remove Bearer from the beginning
return jwt.verify(token,tokenSecret,function (err,decoded) {
if (typeof decoded == "object" && decoded.email == req.body.email) {
return true;
} else {
return false;
}
});
}
使用有效和无效令牌都可以正常工作,但使用无效令牌时我会收到此日志
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
如果我删除 status(401)
,则不会显示此错误日志。为什么会发生这种情况以及如何在不触发此错误日志的情况下将 HTTP STATUS 设置为 401?
解决方法
您正在调用 checkLogin
,它会设置状态代码并回复请求。 checkLogin
完成后,响应已经发送,您不能发送第二个响应。
您缺少的是一些条件逻辑,这些逻辑会在用户未登录的情况下中止处理。通常,这是在中间件中实现的 - 中间件可以在请求到达之前拦截请求处理程序。
我可以看到您的 checkLogin
实现看起来有点像一个中间件函数:它接受一个 next
参数。你可以把它变成这样:
async function checkLogin(req,res,next) {
const loggedIn = await userController.isLoggedIn(req);
if (!loggedIn) {
res.status(401).json({ error: "You are not authorized" });
return;
}
next();
}
router.post("/contacts",checkLogin,function (req,next) {
res.send(userController.getContacts());
});
这告诉 express.js 首先评估 checkLogin
中间件,只有在中间件调用 next()
时才将控制权传递给处理程序。如果它永远不会调用 next - 控制永远不会被传递,因此经过身份验证的用户的“主要逻辑”将永远不会运行。
在此处阅读有关中间件的更多信息:http://expressjs.com/en/api.html#middleware-callback-function-examples
,如果用户未在 checkLogin
中登录,您将发送 401,但此方法已在您的 router.post
中调用,因此它将运行路由处理程序中的下一条语句,即 {{1 }}。但是由于您已经发送了 401 状态,节点在这里抱怨它已经回复了客户端,而您正在尝试发送另一个回复。
您的路由处理程序中需要同时拥有 res.send();
。
res
这应该可以修复错误。
,如果用户未登录,应用程序尝试发送 2 个响应,这就是错误发生的原因。
第一个回复:
async function checkLogin(req,next) {
const loggedIn = await userController.isLoggedIn(req);
if (!loggedIn) {
res.status(401).json({ error: "You are not authorized" });
}
}
如果 login 为 false res.status().json() 将向用户发送响应。
第二个回复 现在代码返回到调用上述函数的那一行,因为没有返回语句来停止/跳过执行
router.post("/contacts",async function (req,next) {
await checkLogin(req,next);
res.send(userController.getContacts());
});
所以在 await checkLogin(req,next);
之后,res.send(userController.getContacts());
被调用,这意味着对于一次调用,您的代码尝试发送 2 个响应。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。