如何在res.send()后干净终止Node.js API中间件代码执行?
问题
我在某API端点实现了验证会话有效性的中间件verifySession,这个中间件会调用validateObjectId函数检查传入的MongoDB ObjectId是否合法。我希望当validateObjectId检测到无效Id时,能终止verifySession的后续执行。
但目前即使返回了错误响应,后续的console.log及正常流程代码仍会执行,导致出现“HTTP响应已结束,无法添加内容”的报错。我尝试过添加或移除return关键字,也知道可以把后续逻辑放在validateObjectId的.then()中,但这会降低代码可读性。我希望在函数顶部的判断逻辑处就能终止整个函数,请问我哪里出错了?
// EDIT 1 BEGIN /** * * @param {mongoose.Types.ObjectId} objectId Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer. * @returns A rejected Promise if the value passed is not a valid MongoDB ObjectId. */ const validateObjectId = async (objectId) => { return new Promise((resolve, reject) => { // Check if the passed-in id is a valid MongoDB ObjectId. Return with an error of it's not. if (!mongoose.Types.ObjectId.isValid(objectId)) { reject({ "error": ERROR_MESSAGES.INVALID_OBJECTID, "errorCode": ERROR_CODES.INVALID_OBJECTID }); } resolve(objectId); }) } // EDIT 1 END // Verify Refresh Token Middleware (which will be verifying the session) let verifySession = async (req, res, next) => { // Grab the refresh token from the request header. let refreshToken = req.header('x-refresh-token'); // Grab the _id from the request header. let _id = req.header('_id'); console.log('ObjectId: ', _id); await validateObjectId(_id) .catch((err) => { console.log('GOT HEREEEEEEEEEEEEEE', err); // return res.send(err); return res.status(STATUS_CODES.UNAUTHORIZED).send(err); }); console.log('GOT HERE BUT SHOULD NOT HAVE'); // Verify the session. }
解决方案
问题出在**await搭配.catch()的错误处理逻辑**:.catch()会捕获Promise的reject并返回一个resolved状态的Promise,所以即使validateObjectId抛出错误,await之后的代码依然会继续执行。
推荐处理方式:用try/catch替代.catch()
把await逻辑放到try/catch块中,捕获错误后执行return就能直接终止后续代码,同时保持代码可读性:
// Verify Refresh Token Middleware (which will be verifying the session) let verifySession = async (req, res, next) => { // Grab the refresh token from the request header. let refreshToken = req.header('x-refresh-token'); // Grab the _id from the request header. let _id = req.header('_id'); console.log('ObjectId: ', _id); try { await validateObjectId(_id); } catch (err) { console.log('GOT HEREEEEEEEEEEEEEE', err); return res.status(STATUS_CODES.UNAUTHORIZED).send(err); } // 仅当ObjectId验证通过时,才会执行以下代码 console.log('验证通过才会执行这里'); // Verify the session. }
额外优化:简化validateObjectId函数
你的validateObjectId是async函数,没必要手动封装Promise,直接抛出错误即可:
const validateObjectId = (objectId) => { if (!mongoose.Types.ObjectId.isValid(objectId)) { throw { "error": ERROR_MESSAGES.INVALID_OBJECTID, "errorCode": ERROR_CODES.INVALID_OBJECTID }; } return objectId; }
(如果要保持async定义,直接throw也会被自动转为reject状态的Promise)
内容的提问来源于stack exchange,提问作者Adrian Constantinescu
相关产品推荐
相关产品推荐

