Nest.js 的设计允许开发者使用统一的方式处理不同类型的服务,如 HTTP、WebSocket 和基于 TCP 的微服务。
这是通过 ArgumentHost
和 ExecutionContext
类实现的,它们提供了跨多种上下文(context)复用 Guards、Interceptors 和 Exception Filters 的能力。
ExecutionContext 类
ExecutionContext
类是一个扩展了 ArgumentsHost
的类。提供了更多关于当前执行过程的信息,比如当前的处理器、类和方法。
ArgumentHost 类
ArgumentHost
是一个包装了当前执行上下文的参数的对象。
我们可以使用 switchToHttp()
、switchToWs()
或 switchToRpc()
方法来获取特定 HTTP、WebSocket 或 RPC 的上下文信息。
ArgumentHost
是 ExecutionContext
的一个超集,它专门用于异常过滤器中。
Exception Filters
创建项目试试:
bash
nest new argument-host -p npm
然后创建一个 filter:
bash
nest g filter HttpException --flat --no-spec
@Catch()
没有声明参数。表示会 catch 所有类型的异常。
如何声明 Exception Filter 来捕获特定类型的异常呢?
catch 一下 HttpException 异常。
AppModule 全局启用下:
AppController 抛出对应错误:
filter 的第一个参数是异常对象,第二个参数是什么呢?
可以看到,它有这些方法。
host.getType 方法取出当前所处上下文。
host.getArgs 方法就是取出当前上下文的 reqeust、response、next 参数。
调用 host.switchToHttp、host.swtichToWs、host.switchToRpc 方法可以分别切换 http、ws、基于 tcp 的微服务上下文。
这样,就可以在 filter 里处理多个上下文的逻辑了:
访问页面:
guard 那 guard 和 interceptor 里如何使用 context 呢?
创建个 guard:
bash
nest g guard role --no-spec --flat
ExecutionContext 扩展了 getClass、getHandler 方法。
这样 Guard、Interceptor 的逻辑可根据目标 class、handler 有没有某些装饰而决定怎么处理。
比如权限验证的时候,我们会先定义几个角色:
自定义装饰器添加 Metadata:
然后在 handler 上添加这个装饰器,参数为 admin:
这样在 Guard 里就可以根据这个 metadata 决定是否放行了:
这里注入的 reflector,并不需要在模块的 provider 声明。
查看页面返回 "Forbidden resource",说明 Guard 生效了,因为 user 是 undefined:
interceptor
在 interceptor 里也有这个 context:
bash
nest g interceptor aaa --no-spec --flat
同样可以通过 reflector 取出 class 或者 handler 上的 metdadata。