如何在 node.js express 中的路由 end() 之后停止中间件序列继续进行
Posted
技术标签:
【中文标题】如何在 node.js express 中的路由 end() 之后停止中间件序列继续进行【英文标题】:How to stop middleware sequence from being proceed after route end() in node.js express 【发布时间】:2018-06-16 06:42:40 【问题描述】: 请帮忙。我无法理解我做错了什么,或者事情是如何解决的。 这只是简单的登录/注册应用程序。我正在使用中间件来防止用户在没有基于 cookie 检查登录的情况下访问 /main 页面。如果未登录,唯一可用的路由是 GET/POST /login 和 GET/POST /register ,在它们的声明进入检查用户是否有特殊 cookie 的中间件之后,如果没有,用户将被重定向到 GET /登录,它工作得很好。如果需要,您可以在 GitHub 上查看整个代码:MNEVO
主要有三个中间件:
-
cookieparse(从请求中解析cookie)
session(对cookie进行编码并写入req.cookie.user)
验证(如果密码是我的,那么您将从 cookie 中获取 JSON,如果不是,它将是未定义的)
我在每个(cookie解析器除外)和登录路由中都插入了console.log。
这就是我得到的输出到 GET /login 路由:
login: 1515262934656
session: 1515262935709
validation: 1515262935709
问题在于,当用户尝试登录时,他成功了,并且路由 POST /login 关闭了连接,响应重定向到 GET /main 页面并将 cookie 写入用户,
.post((req,res)=>
var user = req.body;
//validate input
s2m.login(user , (s2mres)=>
if(s2mres.statusCode === 200)
res.set("Set-Cookie", `one = $session.getOneCookie(user); Path='/'`);
res.set("Location", "/main");
res.status(302).end();
else
res.set("Location", "/login");
res.status(302).end();
);
);
此中间件仍在尝试继续,由于用户一开始没有 cookie,中间件试图将他重定向到 GET /login 页面,当然它失败了,因为之前的路由 POST /login 已经关闭对客户的回应。
LOGIN success: 1515264690286
session: 1515264690378
validation: 1515264690379 // Im redirected to register page at this point(I think)
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11)
at ServerResponse.header (/home/ubuntu/workspace/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/ubuntu/workspace/node_modules/express/lib/response.js:170:12)
at app.get (/home/ubuntu/workspace/server/server.js:86:6)
at Layer.handle [as handle_request] (/home/ubuntu/workspace/node_modules/express/lib/router/layer.js:95:5)
at next (/home/ubuntu/workspace/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/home/ubuntu/workspace/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/ubuntu/workspace/node_modules/express/lib/router/layer.js:95:5)
at /home/ubuntu/workspace/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/home/ubuntu/workspace/node_modules/express/lib/router/index.js:335:12)
session: 1515264691190
validation: 1515264691191
问题:在先前的路由已经关闭连接后,是否有任何方法可以中断中间件序列,或者我弄错了,还有其他方法可以工作吗?
应用
var env = require("./env.js");
var app = require("express")();
var session = require("./session/session.js");
var cookieparser = require("cookie-parser");
var bp = require("body-parser");
var setCookie = require("set-cookie");
var pug = require("pug");
var s2m = require("./s2m/s2m.js");
const ENVIRONMENT = env.c9;
app.get("/get-login-css", (req,res)=>
res.sendFile(__dirname+"/client/css/login.css");
);
app.use(bp.urlencoded( extended: false ));
app.route("/register")
.get((req,res)=>
res.send(pug.renderFile("./pugs/register.pug",)).status(200).end();
)
.post((req,res)=>
var user = req.body;
//validate input
s2m.register(user, (s2mres)=>
if(s2mres.statusCode === 200)
res.set("Set-Cookie", `one = $session.getOneCookie(user); Path='/'`);
res.set("Location", "/main");
res.status(302).end();
else
res.set("Location", "/login?notification=wrong%20login%20or%20password");
res.status(302).end();
);
);
app.route("/login")
.get((req,res)=>
console.log("login: ",Date.now());
res.end(pug.renderFile("pugs/login.pug" , notification: req.query.notification));
)
.post((req,res)=>
var user = req.body;
//validate input
s2m.login(user , (s2mres)=>
if(s2mres.statusCode === 200)
res.set("Set-Cookie", `one = $session.getOneCookie(user); Path='/'`);
res.set("Location", "/main");
res.status(302).end();
else
res.set("Location", "/login");
res.status(302).end();
);
);
app.get("/logout",(req,res)=>
res.set("Set-Cookie", `one = $undefined; Path='/'`);
res.set("Location", "/login");
res.status(302).end();
);
//YOU SHALL NOT PASS (if you don't have login in your cookies)
app.use(cookieparser());
app.use(session.session());
app.use(session.validate());
//ROUTS
app.get("/view-cookie",(req,res)=>
console.log("this is bad");
//user is exist if the code get thus far. so what we well do with it ?
var user = req.cookies.user;
//redirect to the home page
res.send(JSON.stringify(user));
);
app.get("/",(req,res)=>
res.set("Location", "/main");
res.status(302).end();
);
app.get("/main",(req,res)=>
res.send("<div style='text-align: center'> <h1>WELCOME</h1> <br> <a href='/logout'>LOGOUT</a> </div>");
);
app.listen(ENVIRONMENT.port, (err,port)=>
if(!err)
console.log("WE ROLLING! on: ", ENVIRONMENT.domain);
);
session.js
var encdec = require("./encdec.js");
var cookie = require("./cookie.js");
var find = function(cipher)
try
return JSON.parse(encdec.decrypt(cipher));
catch(err)
return undefined;
;
var session = function(callback)
return function(req,res,next)
console.log("session: ",Date.now());
req.cookies.user = find(req.cookies.one);
next();
;
;
var validate = function(callback)
return function(req,res,next)
console.log("validation: ",Date.now());
if(!req.cookies.user)
res.redirect("/register");
// res.status(302).end();
next();
var getOneCookie = function(obj)
return encdec.encrypt(JSON.stringify(array: cookie.wrap(obj)));
;
module.exports =
session,
validate,
getOneCookie
;
【问题讨论】:
【参考方案1】:您以错误的顺序做一些事情。 res.send()
就在那里发送响应。任何对该请求执行进一步操作的尝试都会触发您看到的错误。
所以,改变这个:
res.send(pug.renderFile("./pugs/register.pug",)).status(200).end();
到这里:
res.send(pug.renderFile("./pugs/register.pug",));
.status(200)
是默认值,因此您不需要设置它。并且,res.send()
发送请求,因此您不需要在它之后使用 .end()
。
如果你还想设置状态,那么你必须先设置它:
res.status(200).send(pug.renderFile("./pugs/register.pug",));
其他一些cmets。
你可以替换这种类型的序列:
res.set("Location", "/login");
res.status(302).end();
用这个:
res.redirect("/login");
此外,您应该能够将 pug 直接插入 Express 中的渲染系统,这样您就可以使用它:
res.render("./pugs/register.pug", )
代替:
res.send(pug.renderFile("./pugs/register.pug",))
【讨论】:
谢谢你和一切,但这不是我想要的。关键是,为什么即使响应连接关闭也会触发中间件。 @GrenudiIdunerg - 我认为您对问题的评估不正确。即使请求完成,您认为会触发什么中间件?你修复了所有的实例并尝试了吗? 是的,你是对的,这是一个欺骗输出的时刻。问题只是在字符串行中的单个右花括号中。【参考方案2】: 这是一个欺骗性的时刻。问题只是在字符串行中的一个右花括号中。- 但回答我自己的问题,答案是:
中间件序列随着官方文档中指定的 req\res 周期的终止而自动终止,
无论我是通过重定向关闭连接,还是结束,或结束状态,只要我关闭连接。感谢您的关注。希望它会在这一点上说服其他人文档的可靠性,我对此表示怀疑。
【讨论】:
以上是关于如何在 node.js express 中的路由 end() 之后停止中间件序列继续进行的主要内容,如果未能解决你的问题,请参考以下文章
请求新页面时如何将 AngularJS 路由与 Express (Node.js) 一起使用?
使用 Express.js 在 Node.js 中设置路由的最佳方式