【问题标题】:What's the difference between Interceptor vs Middleware vs Filter in Nest.js?Nest.js 中的拦截器、中间件和过滤器有什么区别?
【发布时间】:2019-07-18 16:57:28
【问题描述】:

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

谢谢

【问题讨论】:

    标签: node.js typescript nestjs


    【解决方案1】:

    正如您在问题中已经暗示的那样,这三个都是非常相似的概念,在很多情况下很难决定,这取决于您的偏好。但我可以概述一下不同之处:

    Interceptors

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

    注册

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

    示例

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

    结论

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

    Middleware

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

    注册

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

    示例

    • FrontendMiddleware:将除 API 之外的所有路由重定向到 index.html,参见 this thread
    • 您可以使用现有的任何快速中间件。有 很多 个库,例如body-parsermorgan

    结论

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

    Exception Filters

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

    注册

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

    示例

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

    结论

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


    所以执行顺序是:

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

    使用所有这三个,您可以在它们的构造函数中注入其他依赖项(如服务,...)。

    【讨论】:

    • 感谢@Kim 的详细说明。你能分享一个使用“ResultMapping”的例子吗?
    • 很高兴您发现它有帮助。 :-) 看看这篇文章。在这里,结果被映射到一个异常。您只需将tap(...) 替换为map(data => ({response: data}),并且您已将任何数据映射到嵌套对象。这是否回答你的问题? stackoverflow.com/a/51918372/4694994
    • 只需在您的main.ts 中添加中间件功能和app.use(),例如app.use(bodyParser.json());
    • 还有 Guards 在每个中间件之后执行,但在任何拦截器或管道之前。
    • @pravindot17 当您执行res.send() 时,会立即发出响应。从逻辑上讲,拦截器在响应发送后无法更改响应。请查看docs:“主要缺点是您失去了与依赖于 Nest 标准响应处理的 Nest 功能的兼容性,例如拦截器和 @HttpCode() 装饰器。”
    【解决方案2】:

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

    【讨论】:

    • 这个很有用。
    【解决方案3】:

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

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

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2021-07-17
      • 1970-01-01
      • 2018-01-31
      • 2012-04-20
      • 2020-12-28
      • 2019-05-01
      • 2019-02-11
      • 1970-01-01
      相关资源
      最近更新 更多