Nestjs的上下文

Nest提供了一些应用类来简化在不同应用上下文之间编写应用。这些应用可以用于创建通用的守卫,过滤器和拦截器,可以工作在控制器,方法和应用上下文中。

这一章节就说一下我们之前看过的ArgumentsHostExecutionContext两个类.

ArgumentsHost

ArgumentsHost类提供了获取传递给处理程序的参数。它允许选择合适的上下文(例如HTTP,RPC(微服务)或者Websockets)来从框架中获取参数。框架提供了ArgumentsHost的实例,作为host参数提供给需要获取的地方

ArgumentsHost简单地抽象为处理程序参数。例如,在HTTP应用中(使用@nestjs/platform-express时),host对象封装了Express的[request, response, next] 数组,request是一个request对象,response是一个response对象,next是控制应用的请求响应循环的函数。此外,在GraphQL应用中,host包含[root, args, context, info]数组。

当构建通用的守卫,过滤器和拦截器时,意味着要跨应用上下文运行,我们需要在当前运行时定义应用类型。可以使用 ArgumentsHostgetType()方法。

1
2
3
4
5
6
7
8
if (host.getType() === 'http') {
// do something that is only important in the context of regular HTTP requests (REST)
} else if (host.getType() === 'rpc') {
// do something that is only important in the context of Microservice requests
} else if (host.getType<GqlContextType>() === 'graphql') {
// do something that is only important in the context of GraphQL requests
}

要获取传递给处理程序的参数数组,使用host对象的getArgs()方法。

1
const [req, res, next] = host.getArgs();Copy to clipboardErrorCopied

可以使用getArgByIndex()根据索引获取指定参数:

1
2
const request = host.getArgByIndex(0);
const response = host.getArgByIndex(1);Copy to clipboardErrorCopied

在这些例子中我们通过索引来获取请求响应对象,这并不推荐,因为它将应用和特定上下文耦合

为了使代码更健壮,更可复用,你可以在程序中使用host对象的应用方法来切换合适的应用上下文

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Switch context to RPC.
*/
switchToRpc(): RpcArgumentsHost;
/**
* Switch context to HTTP.
*/
switchToHttp(): HttpArgumentsHost;
/**
* Switch context to WebSockets.
*/
switchToWs(): WsArgumentsHost;

使用 switchToHttp() 方法重写前面的例子, host.switchToHttp()帮助方法调用一个HTTP应用的HttpArgumentsHost对象. HttpArgumentsHost对象有两个有用的方法,我们可以用来提取期望的对象。我们也可以使用Express类型的断言来返回原生的Express类型对象:

1
2
3
const ctx = host.switchToHttp();
const request = ctx.getRequest<Request>();
const response = ctx.getResponse<Response>();

类似地,WsArgumentsHostRpcArgumentsHost有返回微服务和WebSockets上下文的方法,以下是WsArgumentsHost的方法:

1
2
3
4
5
6
7
8
9
10
export interface WsArgumentsHost {
/**
* Returns the data object.
*/
getData<T>(): T;
/**
* Returns the client object.
*/
getClient<T>(): T;
}Copy to clipboardErrorCopied

以下是RpcArgumentsHost的方法:

1
2
3
4
5
6
7
8
9
10
11
export interface RpcArgumentsHost {
/**
* Returns the data object.
*/
getData<T>(): T;

/**
* Returns the context object.
*/
getContext<T>(): T;
}

ExecutionContext

ExecutionContext扩展了ArgumentsHost,提供额外的当前运行线程信息。和ArgumentsHost类似,Nest在需要的时候提供了一个ExecutionContext的实例, 例如守卫的canActivate()方法和拦截器的intercept()方法,它提供以下方法:

1
2
3
4
5
6
7
8
9
10
11
export interface ExecutionContext extends ArgumentsHost {
/**
* Returns the type of the controller class which the current handler belongs to.
*/
getClass<T>(): Type<T>;
/**
* Returns a reference to the handler (method) that will be invoked next in the
* request pipeline.
*/
getHandler(): Function;
}

getHandler()方法返回要调用的处理程序的引用。getClass()方法返回一个特定处理程序所属的控制器类。例如,一个HTTP上下文,如果当前处理的是一个POST请求,在CatsController中绑定create()方法。getHandler()返回create()方法和getClass()方法所在的CatsController类的引用(不是实例)。

1
2
const methodKey = ctx.getHandler().name; // "create"
const className = ctx.getClass().name; // "CatsController"Copy to clipboardErrorCopied

能同时获取当前类和处理方法的引用的能力提供了极大的灵活性。最重要的是,它给我们提供了通过@SetMetadata()装饰器来操作守卫或拦截器元数据的方法(在守卫一节用到过)。

这一节确实没想到能说什么,所以只是把官方文档的内容摘录了一下,没有相关的示例。

之所以有这一节,主要是因为前边守卫、拦截器等都用到了上下文,所以来说一下。

作者

胡兆磊

发布于

2023-02-24

更新于

2023-02-24

许可协议