乐闻世界logo
搜索文章和话题

Nestjs 项目中拦截器,中间件,过滤器的区别是什么?

9 个月前提问
5 个月前修改
浏览次数106

3个答案

1
2
3

正如您已经在问题中描述的那样,这三个都是非常相似的概念,在很多情况下很难决定,这取决于您的偏好。

但我可以概述一下这些差异:

拦截器

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

登记

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

例子

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

结论

与中间件相比,我喜欢注册更接近路由处理程序。但存在一些限制,例如,当您在路由处理程序中发送 response特定于库的对象时,您无法设置响应代码或使用拦截器更改响应,请参阅文档@Res()

中间件

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

登记

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

例子

  • FrontendMiddleware:将除 API 之外的所有路由重定向到 index.html,请参阅此线程
  • 您可以使用任何现有的快速中间件。有_很多_图书馆,例如body-parsermorgan

结论

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

异常过滤器

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

登记

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

例子

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

结论

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


所以执行顺序是:

中间件 -> 拦截器 -> 路由处理程序 -> 拦截器 -> 异常过滤器(如果抛出异常)

对于这三个工具,您可以在其构造函数中注入其他依赖项(如服务等)。

2024年6月29日 12:07 回复

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

在此输入图像描述

2024年6月29日 12:07 回复

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

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

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

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

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

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

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

2024年6月29日 12:07 回复

你的答案