You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express错误处理中间件无法正常捕获InvalidKeyError问题

解决Express中Async路由抛出的自定义错误无法被错误处理中间件捕获的问题

问题根源

Express 默认不会自动捕获异步路由处理函数中抛出的错误,这些错误会以未处理的 Promise 拒绝形式存在,进而导致应用崩溃,而不会被错误处理中间件捕获。

反观全局路由中的 NotFoundError 能正常被捕获,是因为 app.all('*') 的处理函数是同步函数,Express 会自动捕获同步函数抛出的错误并传递给错误处理中间件。

解决方案

方案1:使用 try/catch 手动捕获错误并传递给 next

修改你的 checkAPIKeyRouter 代码,在异步函数内部用 try/catch 包裹逻辑,捕获错误后通过 next(err) 传递给错误处理中间件:

import express from 'express';
import { Request, Response, NextFunction } from 'express';
import { InvalidKeyError } from '../errors/invalid-api-key-error';
import { APIKey } from '../models/api-key-model';
import { Hash } from '../services/hash';

const router = express.Router();

router.get('/api/checkkey', async (req: Request, res: Response, next: NextFunction) => {
    try {
        const suppliedKey = req.get('key');
        const suppliedSecret = req.get('secret');

        if (!suppliedKey || !suppliedSecret)
            throw new InvalidKeyError('Key or secret not passed');

        const storedAPIKey = await APIKey.findOne({ key: suppliedKey });

        if (!storedAPIKey)
            throw new InvalidKeyError('Key does not exist');

        if (!Hash.compareKeys(suppliedKey, suppliedSecret, storedAPIKey.salt))
            throw new InvalidKeyError('Key and secret do not correspond')

        res.send('Hi there');
    } catch (err) {
        next(err); // 将错误传递给错误处理中间件
    }
});

export { router as checkAPIKeyRouter };

方案2:创建通用异步错误处理包装函数

如果项目中有多个异步路由,推荐封装一个通用的包装函数,自动处理异步错误的传递,避免重复写 try/catch:

首先创建一个工具函数(比如 utils/async-handler.ts):

import { Request, Response, NextFunction } from 'express';

export const asyncHandler = (fn: (req: Request, res: Response, next: NextFunction) => Promise<any>) => {
    return (req: Request, res: Response, next: NextFunction) => {
        fn(req, res, next).catch(next);
    };
};

然后在路由中使用这个包装函数:

import express from 'express';
import { InvalidKeyError } from '../errors/invalid-api-key-error';
import { APIKey } from '../models/api-key-model';
import { Hash } from '../services/hash';
import { asyncHandler } from '../utils/async-handler';

const router = express.Router();

router.get('/api/checkkey', asyncHandler(async (req, res) => {
    const suppliedKey = req.get('key');
    const suppliedSecret = req.get('secret');

    if (!suppliedKey || !suppliedSecret)
        throw new InvalidKeyError('Key or secret not passed');

    const storedAPIKey = await APIKey.findOne({ key: suppliedKey });

    if (!storedAPIKey)
        throw new InvalidKeyError('Key does not exist');

    if (!Hash.compareKeys(suppliedKey, suppliedSecret, storedAPIKey.salt))
        throw new InvalidKeyError('Key and secret do not correspond')

    res.send('Hi there');
}));

export { router as checkAPIKeyRouter };

方案3:升级到 Express 5+(可选)

Express 5 版本开始会自动捕获异步路由处理函数中抛出的错误,并将其传递给错误处理中间件,无需手动处理。如果项目允许升级依赖,可以直接升级 Express 版本。

验证修改

完成上述任一修改后,再次触发 InvalidKeyError,错误会被错误处理中间件正常捕获,并返回和 NotFoundError 一致的规范 JSON 响应。

内容的提问来源于stack exchange,提问作者Papaya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 00:20:26