简体   繁体   中英

How to stop middleware sequence from being proceed after route end() in node.js express

  • Please help. I cant understand am I doing something wrong or is that how the things work around.
  • It is just simple login/register application. I'm using middleware to prevent user from being able get to /main page if their are not logged in based on cookie check. The only routes that is available if one is not logged in is GET/POST /login, and GET/POST /register ,after their declaration goes middleware that checks if user have special cookie, if not, a user will be redirected to GET /login, and it works just fine.

You can view the whole code if needed on GitHub: MNEVO


there is three main middlewares:

  1. cookieparse(parse cookie from request)
  2. session(encode cookie and write it to req.cookie.user)
  3. validate(if cipher was mine then you'll get JSON out of cookie if not , it will be undefined)

I inserted console.log in each (except cookie parser) and in login route.


And this is what output i get what going to GET /login route:

 login:  1515262934656  
 session:  1515262935709  
 validation:  1515262935709 

  • The problem is that when user try to log in, and he did, and route POST /login closes the connection responding with redirect to GET /main page and writing cookie to a user,
.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();
        }
    });
});
  • this middlewares is still trying proceed, and since a user don't had cookie in the first place the middleware is trying to redirect him to GET /login page, and of course it fail because previous route POST /login is already closed the response to a client.
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
  • The Question: is there any way to break middleware sequence after previous route is already closed a connection, or am I getting it wrong and there is some other way this things work ?

application

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
};

You're doing a few things in the wrong order. res.send() sends the response right there. Any attempt to do further things with that request will trigger the error you see.

So, change this:

res.send(pug.renderFile("./pugs/register.pug",{})).status(200).end();

to this:

res.send(pug.renderFile("./pugs/register.pug",{}));

.status(200) is the default so you don't need to set it. And, res.send() sends the request so you don't need .end() after it.

If you still wanted to set the status, then you have to set it first:

res.status(200).send(pug.renderFile("./pugs/register.pug",{}));

Some other comments.

You can replace this type of sequence:

res.set("Location", "/login");
res.status(302).end();

with this:

res.redirect("/login");

In addition, you should be able to plug pug directly into the rendering system in Express so you can just use this:

res.render("./pugs/register.pug", {})

instead of:

res.send(pug.renderFile("./pugs/register.pug",{}))
  • It was a moment of deception with the out put. The problem was just in a single closing curly brace in String line.

    - But answering my own question, the answers is:


middleware sequence is automatically terminated with termination of req\\res cycle as specified in the official documentation,


no matter if I close connection with redirect, or end, or end status , as long as I close the connection. Thanks to your attention. Hope it will convince others in documentation reliability at this point, which I had doubts about.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM