Javascript Express.js:执行不会';在错误处理程序之后不要停止。为什么?
我已经编写了一个express应用程序来创建RESTAPI 据我所知,如果我发送一个带有无效令牌的头,jwt.verify会设置err(JsonWebTokenError),它会传递给我的错误处理程序,并发送一个401:Javascript Express.js:执行不会';在错误处理程序之后不要停止。为什么?,javascript,node.js,express,Javascript,Node.js,Express,我已经编写了一个express应用程序来创建RESTAPI 据我所知,如果我发送一个带有无效令牌的头,jwt.verify会设置err(JsonWebTokenError),它会传递给我的错误处理程序,并发送一个401: res.status(401).send({ success: false, message: err.name }); 执行也应该结束。但我得到的却是: Start token verification Error before: JsonW
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)
因此,在错误处理之后,路由处理程序被执行,我不明白为什么
我的代码(仅相关位):
我使用此中间件验证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);
});
});
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()
。如果令牌验证失败,则调用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();
}
});
}
在路由处理程序中也发生了类似的情况:
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);
});
});
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);
}
我一直在思考这个问题,我有一个疑问,我们不是在同步转换代码吗?我们正在做所有这些
if-else
语句。执行必须等待异步调用才能继续执行,否则我会丢失一些东西?@mvillar这里的异步函数是jwt.verify()
,我们在调用next()
之前等待它完成(在调用jwt.verify()
的完成回调中调用它)。if/else
仅用于区分要调用的next()
。