如何在@inversifyjs/http-express中规范实现NotFound(404)API路由
如何在@inversifyjs/http-express中规范实现NotFound(404)API路由
我之前用@inversifyjs/http-express搭API的时候也卡过这个404路由的问题,官方文档这块确实没给明确指引,后来折腾了一阵,发现其实可以利用Express的原生特性优雅解决,刚好和你现在的思路对上,给你梳理下更规范的实现方式:
因为@inversifyjs/http-express本质是Express的封装,所以我们完全可以沿用Express的中间件优先级逻辑——把404中间件放在所有路由注册完成之后,这样所有匹配不到已定义接口的请求,都会自动走到这个中间件里。
基础实现方案(和你的思路一致,优化细节)
这种方式简单直接,不需要依赖额外的DI注入,适合大多数场景:
import { Container } from 'inversify'; import { InversifyExpressHttpAdapter } from '@inversifyjs/http-express'; import { Request, Response } from 'express'; import { HttpStatusCode } from '你的状态码枚举路径'; // 假设你已经实现了这些全局中间件和过滤器 import CorsMiddleware from './middlewares/cors'; import HelmetMiddleware from './middlewares/helmet'; import RateLimitMiddleware from './middlewares/rate-limit'; import CookieParserMiddleware from './middlewares/cookie-parser'; import LoggerMiddleware from './middlewares/logger'; import GlobalErrorFilter from './filters/global-error'; export class Server { private adapter: InversifyExpressHttpAdapter; constructor(private readonly container: Container) { this.adapter = new InversifyExpressHttpAdapter(this.container, { useJson: true, }); // 先注册所有全局中间件 this.adapter.applyGlobalMiddleware(CorsMiddleware); this.adapter.applyGlobalMiddleware(HelmetMiddleware); this.adapter.applyGlobalMiddleware(RateLimitMiddleware); this.adapter.applyGlobalMiddleware(CookieParserMiddleware); this.adapter.applyGlobalMiddleware(LoggerMiddleware); // 注册全局错误过滤器 this.adapter.useGlobalFilters(GlobalErrorFilter); } public async getApp() { // 关键:先让Inversify构建所有已注册的控制器路由 const app = await this.adapter.build(); // 再挂载404中间件,确保它是最后一个被执行的中间件 app.use(notFoundMiddleware); return app; } } // 独立的404中间件,返回标准化的错误响应 function notFoundMiddleware(req: Request, res: Response) { return res.status(HttpStatusCode.NOT_FOUND).json({ statusCode: HttpStatusCode.NOT_FOUND, message: `Route '${req.originalUrl}' not found`, data: null, }); }
进阶:把404中间件纳入DI容器管理
如果你的404处理需要依赖容器中的其他服务(比如自定义的错误日志服务),可以把中间件改成可注入的类:
import { injectable } from 'inversify'; import { Request, Response } from 'express'; import { HttpStatusCode } from '你的状态码枚举路径'; // 用@injectable()装饰,让它能被Inversify容器管理 @injectable() export class NotFoundMiddleware { // 如果需要依赖其他服务,直接在构造函数注入即可 constructor() {} handle(req: Request, res: Response) { return res.status(HttpStatusCode.NOT_FOUND).json({ statusCode: HttpStatusCode.NOT_FOUND, message: `Route '${req.originalUrl}' not found`, data: null, }); } } // 然后在Server类中调整: public async getApp() { const app = await this.adapter.build(); // 从容器中获取中间件实例 const notFoundMiddleware = this.container.get<NotFoundMiddleware>(NotFoundMiddleware); // 绑定this上下文后挂载 app.use(notFoundMiddleware.handle.bind(notFoundMiddleware)); return app; }
核心注意点
- 一定要在
adapter.build()之后挂载404中间件:因为build()方法会把所有通过@controller装饰器注册的路由都绑定到Express实例上,中间件是按注册顺序执行的,放在最后才能确保所有未匹配的请求都被捕获。 - 不需要纠结Inversify有没有内置的404处理:官方确实没做这个封装,因为底层Express已经提供了完善的中间件机制,直接用就好,这也是社区里的通用做法。




