Nest is a platform-agnostic framework.
上篇文章给大家说过Nest中的模块化思想,模块化是组织业务代码的方式,我们还需要用一个传输层(transport layer)
将业务暴露出去得以执行,例如Http服务器的话要定义路由找到执行方法,websocket则是定义一个gateway接收所有事件并进行分发。在我理解,平台不可知论说的正是这种能按照所需的暴露服务方式,灵活地进行开发与管理。这也就会意味着,不同暴露方式则会产生不一样的上下文(Context)。
下面来看看Nest中是如何进行设计的。
应用上下文我们创建Nest应用,是通过@nestjs/core
里面的NestFactory
方法进行创建的,先看看代码
export declare class NestFactoryStatic {
create<T extends INestApplication = INestApplication>(module: any, options?: NestApplicationOptions): Promise<T>;
create<T extends INestApplication = INestApplication>(module: any, httpAdapter: AbstractHttpAdapter, options?: NestApplicationOptions): Promise<T>;
createMicroservice<T extends object>(module: any, options?: NestMicroserviceOptions & T): Promise<INestMicroservice>;
createApplicationContext(module: any, options?: NestApplicationContextOptions): Promise<INestApplicationContext>;
// 省略部分代码
}
可以看到,这里有几个创建应用的方法:
create
是创建一个Http Server App:INestApplication
createMicroservice
是创建一个微服务应用:INestMicroservice
createApplicationContext
则是创建一个独立的应用,没有任何网络监听。
Standalone App
Standalone App比较简单,是直接暴露入口文件作为执行入口,没有绑定socket的就是独立应用。一般是用在CronJob或者Cli
一般用得比较多的就是select()
和get()
方法,ts定义如下面代码:
export interface INestApplicationContext {
select<T>(module: Type<T> | DynamicModule): INestApplicationContext;
get<TInput = any, TResult = TInput>(typeOrToken: Type<TInput> | Abstract<TInput> | string | symbol, options?: {
strict: boolean;
}): TResult;
// 省略部分代码
}
之前将模块化的时候说过,Nest是用了IoC作为模块化管理的,这两个方法就是让我们可以从应用直接找到对应的Provider,也就是业务代码。
get
方法定义了从App中获取依赖项(Provider)
const app = await NestFactory.createApplicationContext(AppModule);
const tasksService = app.get(TasksService);
这里默认是从AppModule
去查找Provider的,通过select
则可以制定模块去找。
const app = await NestFactory.createApplicationContext(AppModule);
const tasksService = app.select(TasksModule).get(TasksService, { strict: true });
独立应用比较简单,可以理解为一般的js脚本,也就是没有transport layer。而需要网络传输的才是重点的使用领域。
Http App和MicroService AppHttp App和MicroService App都需要网络服务,每个请求过来时,都会有一个执行上下文。
有两种执行上下文,分别是ArgumentsHost
和ExecutionContext
。
先看看ArgumentsHost的定义
export declare type ContextType = 'http' | 'ws' | 'rpc';
export interface ArgumentsHost {
getArgs<T extends Array<any> = any[]>(): T;
getArgByIndex<T = any>(index: number): T;
switchToRpc(): RpcArgumentsHost;
switchToHttp(): HttpArgumentsHost;
switchToWs(): WsArgumentsHost;
getType<TContext extends string = ContextType>(): TContext;
}
这个上下文主要定义了不同transport的上下文对象,可以看到,Nest的上下文类型定义了http
、ws
和rpc
三种。
getData
和getClient
方法rpc定义了getData
和getContext
方法
可以通过getType
方法获得当前的上下文类型,例如:
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
}
当然上下文也可以进行拓展,例如GraphQL
的上下文继承了Nest的ExecutionContextHost
,然后定义了root
, args
, context
,和info
四个属性。
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
export declare class GqlExecutionContext extends ExecutionContextHost implements GraphQLArgumentsHost {
static create(context: ExecutionContext): GqlExecutionContext;
getType<TContext extends string = GqlContextType>(): TContext;
getRoot<T = any>(): T;
getArgs<T = any>(): T;
getContext<T = any>(): T;
getInfo<T = any>(): T;
}
ExecutionContext
ExecutionContext其实是直接继承了ArgumentsHost,然后拓展了获得controller的类和调用的方法。
export interface ExecutionContext extends ArgumentsHost {
getClass<T = any>(): Type<T>;
getHandler(): Function;
}
Provider的注入范围(injection scopes)
这里的注入还是指Nest的IoC机制中的注入。
provider的注入范围指的是一种来获得所需的提供者生命周期行为的机制。
有三种:
DEFAULT
,默认的注入范围,provider以单例方式在整个应用程序中共享;REQUEST
,专门为每个传入请求创建一个新的提供者实例。该实例在请求完成处理后被垃圾回收;TRANSIENT
,在注入时都将创建一个新的专用实例。
用法就是在Injectable
装饰器作为参数传入进去。
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {}
在介绍上下文的时候讲到这个注入范围,主要是因为REQUEST
范围,有时需要在Provider中获取到请求上下文,这种时候就一定要将Provider定义为REQUEST scope
。
import { Injectable, Scope, Inject } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {
constructor(@Inject(REQUEST) private request: Request) {}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)