Nest.js中的Interceptor,Middleware和Filter之间有什么区别?

Bil*_*ill 10 node.js typescript nestjs

Nest.js框架中的拦截器,过滤器和中间件有什么区别?什么时候应该使用它们中的一个并使其胜于另一个?

谢谢

dem*_*isx 56

对于我们这些在视觉上更好地“理解”的人,我根据最新v6.10版本创建了这个 NestJs 管道图。请随时指出任何不准确之处。如果需要,我会及时查看并更新它。

在此处输入图片说明

  • 这非常有用。 (8认同)
  • @buryo 确实如此。 (3认同)
  • 我想知道这张图片是否代表2022年? (2认同)

Kim*_*ern 28

正如您已经暗示的那样,这三个概念都是非常相似的,在很多情况下,很难决定并归结为您的偏好。但我可以概述一下这些区别:

拦截器

拦截器可以在调用路由处理程序之前之后访问响应/请求。

注册

  • 直接在@UseInterceptors()控制器或控制器范围内的控制器类中
  • 在全球范围app.useGlobalInterceptors()main.ts

例子

  • LoggingInterceptor:在路由处理程序之前请求,然后在其结果之后请求。测量时间。
  • ResultMapping:转换null[]结果或将结果包装在响应对象中:users->{users: users}

结论

与中间件相比,我更喜欢注册更接近路由处理程序。但是有一些限制,例如,当您在路由处理程序中使用responsewith @Res()对象时,您无法设置响应代码,并且不能使用拦截器。

中间件

仅在调用路由处理程序之前调用中间件。您可以访问响应对象,但没有路由处理程序的结果。它们基本上是表达的中间件功能。

注册

  • 在模块中,非常灵活的选择相关路由的方式(带通配符,按方法...)
  • 在全球范围app.use()main.ts

例子

  • FrontendMiddleware:将除API外的所有路由重定向到index.html,请参阅文章
  • 您可以使用任何现成的快速中间件。有大量的库,例如body-parsermorgan

结论

中间件的注册非常灵活,例如:适用于除一条路径之外的所有路由。但是,由于它们已在模块中注册,因此在查看其方法时,您可能不会意识到它适用于控制器。可以利用现有的所有快速中间件库也很棒。

异常过滤器

在路由处理程序和拦截器之后调用异常过滤器。它们是在响应消失之前最后进行更改的地方。

注册

  • 直接在@UseFilters()控制器或控制器范围内的控制器类中
  • 全球app.useGlobalFilters()main.ts

例子

  • UnauthorizedFilter:映射为用户易于理解的消息
  • NotFoundFilter:将所有未找到的路由(不是api的一部分)映射到index.html

结论

异常过滤器的基本用例提供了可理解的错误消息(隐藏技术细节)。但是,还有其他创造性的使用方式:当您为单个页面应用程序提供服务时,通常所有路由都应重定向到index.htmlAPI路由之外的其他地址。在这里,您可以重定向NotFoundException。有些人可能会发现这个聪明的人很hacky。你的选择。;-)


因此执行顺序为:

Middleware -> Interceptors -> Route Handler -> Interceptors -> Exception Filter (if exception is thrown)

With all three of them, you can inject other dependencies (like services,...) in their constructor.

  • 只需在你的 `main.ts` 中使用 `app.use()` 添加中间件函数,例如 `app.use(bodyParser.json());` (2认同)
  • 还有一些守卫在每个中间件之后、任何拦截器或管道之前执行。 (2认同)
  • @pravindot17 当您执行 `res.send()` 时,响应会立即发送出去。从逻辑上讲,拦截器在发送响应后无法更改响应。请查看[文档](https://docs.nestjs.com/controllers#appendix-library-specific-approach):“主要缺点是失去与依赖于 Nest 标准响应处理的 Nest 功能的兼容性,例如拦截器和 @HttpCode() 装饰器。” (2认同)

Jes*_*ter 8

我假设您的意思是管道而不是过滤器,因为过滤器主要与异常处理相关联。

肯定有一些重叠,因为中间件是组合任何 Web 应用程序的灵活方式,但更多的是通用概念(创建函数堆栈以构建管道)。其他的是 Nest 特定的概念,因此与依赖注入之类的东西更自然地联系在一起。

管道用于转换输入数据(并可选择进行验证)。

拦截器非常简洁,因为它们可以转换传入和传出 API 的数据。它们使您能够通过使用可观察流来改变原始处理程序将返回的内容。您可能需要使用两个中间件(在处理程序的任一侧)来实现这一点。

当您想转换进入处理程序的数据时,请使用管道。

当需要双向转换时使用拦截器。

当您希望更接近于构建 Web 应用程序的传统(例如 Express)方式,或者希望一次更广泛地将功能应用到许多处理程序时(在您的代码中浮动的装饰器较少),请使用中间件。