javascript - Express.js : Execution doesn't stop after error handler. 为什么?

标签 javascript node.js express

我编写了一个 Express 应用程序来创建 REST API。

据我了解,如果我发送带有无效 token 的 header ,jwt.verify 会设置 err (JsonWebTokenError),该错误会传递到我的错误处理程序并发送 401:

res.status(401).send({
        success: false,
        message: err.name
});

执行应该结束。但相反,我得到了这个:

Start token verification
Error before: JsonWebTokenError
JsonWebTokenError: invalid signature
at Object.module.exports.verify (/srv/lonja/node_modules/jsonwebtoken/index.js:129:17)
at /srv/lonja/app/routes/api.js:76:17
at Layer.handle [as handle_request] (/srv/lonja/node_modules/express/lib/router/layer.js:82:5)
at trim_prefix (/srv/lonja/node_modules/express/lib/router/index.js:302:13)
at /srv/lonja/node_modules/express/lib/router/index.js:270:7
at Function.proto.process_params (/srv/lonja/node_modules/express/lib/router/index.js:321:12)
at next (/srv/lonja/node_modules/express/lib/router/index.js:261:10)
at Function.proto.handle (/srv/lonja/node_modules/express/lib/router/index.js:166:3)
at router (/srv/lonja/node_modules/express/lib/router/index.js:35:12)
at Layer.handle [as handle_request] (/srv/lonja/node_modules/express/lib/router/layer.js:82:5)
This is the last message related to[object Object]
GET /api/home_gallery/ 401 20.834 ms - 47
_http_outgoing.js:335
throw new Error('Can\'t set headers after they are sent.');
      ^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/srv/lonja/node_modules/express/lib/response.js:700:10)
at ServerResponse.send (/srv/lonja/node_modules/express/lib/response.js:154:12)
at ServerResponse.json (/srv/lonja/node_modules/express/lib/response.js:240:15)
at /srv/lonja/app/routes/api.js:214:17
at /srv/lonja/node_modules/mongoose/node_modules/kareem/index.js:103:16
at process._tickCallback (node.js:355:11)

所以,在错误处理之后,路由处理程序被执行,我不明白为什么。

我的代码(只是相关位):

var User = require('../models/user');
var myImage = require('../models/image');
var jwt = require('jsonwebtoken');
var config = require('../../config');

// super secret for creating tokens
var superSecret = config.secret;

module.exports = function(app, express) {

    var apiRouter = express.Router();

我使用这个中间件来验证 jsonwebtoken:

   // route middleware to verify a token
apiRouter.use(function(req, res, next) {
    // do logging
    console.log('Start token verification');

    // check header or url parameters or post parameters for token
    var token = req.body.token || req.params.token || req.headers['x-access-token'];

    // decode token
    // verifies secret and checks exp
    if (token) {
        jwt.verify(token, superSecret, function(err, decoded) {
            if (err) {
                return next(err);
            }
            // if everything is good, save to request for use in other routes
            else req.decoded = decoded;
        });
    }
    // if there is no token
    // return an HTTP response of 401 (access unauthorized) and an error message
    else {
        var noToken = new Error('Error_NoTokenProvided');
        return next(noToken);
    }
    next(); // make sure we go to the next routes and don't stop here
});

在代码的后面,我得到了这个路由处理程序:

apiRouter.route('/home_gallery')
// get all the images
.get(function(req, res) {
    myImage.find(function(err, images) {
        if (err) res.send(err);
        // return the users
        res.json(images);
    });
});

最后,最后一个中间件进行错误处理:

apiRouter.use(function(err, req, res, next) {
    console.log('Error before: ' + err.name);
    if (err.name == 'Error_NoTokenProvided' ||
        err.name == 'JsonWebTokenError') {
        res.status(401).send({
            success: false,
            message: err.name
        });
    } else if (err.name == 'TokenExpiredError') {
        res.redirect('/login');
    } else {
        res.status(500).send({
            success: false,
            message: err.name
        });
    }
    console.log(err.stack);
    console.log('This is the last message related to' + req);
});

最佳答案

问题似乎是这样的:

if (token) {
    jwt.verify(token, superSecret, function(err, decoded) {
        if (err) {
            return next(err);
        }
        // if everything is good, save to request for use in other routes
        else req.decoded = decoded;
    });
} else { ... }
next();

由于 jwt.verify() 是一个异步方法,因此在该函数调用之后处理会继续,这意味着调用底部 next()。如果 token 验证失败,则调用next(err);换句话说,您调用 next() 两次。

一种可能的解决方案是:

if (token) {
    // We use `return` only to stop further processing of the middleware,
    // we don't actually care about the return value from `jwt.verify()`.
    return jwt.verify(token, superSecret, function(err, decoded) {
        if (err) {
            return next(err);
        }
        // if everything is good, save to request for use in other routes
        else {
          req.decoded = decoded;
          next();
        }
    });
}

您的路由处理程序中也发生了类似的事情:

if (err) res.send(err);
// return the users
res.json(images);

如果设置了 err,则同时调用 res.send()res.json(),因为调用 res .send() 不会奇迹般地停止对其余代码的进一步处理。

可以使用与上面类似的解决方案:

if (err) return res.send(err);
res.json(images);

或者,如果您愿意的话:

if (err) {
  res.send(err);
} else {
  res.json(images);
}

关于javascript - Express.js : Execution doesn't stop after error handler. 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30036567/

相关文章:

javascript - JSON.stringify 不代表被字符串化的对象

node.js - 错误 : callback function required

javascript - Express.js,意外的 token <

javascript - 可以在不使用中间件函数的情况下增强 express.js req 和 res 变量吗?

php - 如何将 var url 放入 JavaScript 中?

javascript - JavaScript 递归函数调用中变量的最终值

JavaScript、nodejs : give a "string not found" messege on console. 日志

javascript - Node.js socket.io 的 Dojox 套接字异常

javascript - 从跨度导入文本

node.js - 用于 redis 从站的 HAproxy