NestJS 源码解析:路由系统
深入 RouterExplorer 和 RouterExecutionContext,揭秘请求的分发与处理。
路由注册流程
NestApplication.listen()
↓
RoutesResolver.resolve()
↓
RouterExplorer.explore()
↓
HttpAdapter.bindHandler()
请求作用域处理
当控制器或其依赖是请求作用域时,NestJS 会为每个请求创建新实例:
// packages/core/router/router-explorer.ts
private applyCallbackToRouter(...) {
const isRequestScoped = !instanceWrapper.isDependencyTreeStatic();
const proxy = isRequestScoped
? this.createRequestScopedHandler(/*...*/) // 请求作用域
: this.createCallbackProxy(/*...*/); // 静态作用域
}
public createRequestScopedHandler(
instanceWrapper: InstanceWrapper,
requestMethod: RequestMethod,
moduleRef: Module,
moduleKey: string,
methodName: string,
) {
const { instance } = instanceWrapper;
const collection = moduleRef.controllers;
const isTreeDurable = instanceWrapper.isDependencyTreeDurable();
return async <TRequest, TResponse>(req: TRequest, res: TResponse, next: () => void) => {
try {
// 获取或创建请求上下文 ID
const contextId = this.getContextId(req, isTreeDurable);
// 为当前请求加载控制器实例
const contextInstance = await this.injector.loadPerContext(
instance,
moduleRef,
collection,
contextId,
);
// 创建并执行代理
await this.createCallbackProxy(
contextInstance,
contextInstance[methodName],
methodName,
moduleKey,
requestMethod,
contextId,
instanceWrapper.id,
)(req, res, next);
} catch (err) {
// 异常处理...
}
};
}
关键点:
isDependencyTreeStatic()判断整个依赖树是否都是静态的isDependencyTreeDurable()判断是否是持久化作用域loadPerContext()为特定上下文加载实例
RoutesResolver
解析所有控制器的路由:
// packages/core/router/routes-resolver.ts
export class RoutesResolver {
public resolve(applicationRef: HttpServer, globalPrefix: string) {
const modules = this.container.getModules();
modules.forEach(({ controllers, metatype }, moduleName) => {
// 获取模块路径前缀
const modulePath = this.getModulePathMetadata(metatype);
// 遍历控制器
controllers.forEach((wrapper, token) => {
const { instance, metatype } = wrapper;
// 获取控制器路径
const paths = this.routerExplorer.extractRouterPath(metatype);
const host = this.getHostMetadata(metatype);
// 探索并注册路由
paths.forEach(path => {
this.routerExplorer.explore(
wrapper,
moduleName,
applicationRef,
host,
{
ctrlPath: path,
modulePath,
globalPrefix,
},
);
});
});
});
}
}
RouterExplorer
探索控制器的路由方法:
// packages/core/router/router-explorer.ts
export class RouterExplorer {
public explore(
instanceWrapper: InstanceWrapper,
moduleKey: string,
httpAdapterRef: HttpServer,
host: string | RegExp | Array<string | RegExp>,
routePathMetadata: RoutePathMetadata,
) {
const { instance } = instanceWrapper;
// 扫描所有路由方法
const routerPaths = this.pathsExplorer.scanForPaths(instance);
// 注册到 HTTP 适配器
this.applyPathsToRouterProxy(
httpAdapterRef,
routerPaths,
instanceWrapper,
moduleKey,
routePathMetadata,
host,
);
}
// 注册路由
public applyPathsToRouterProxy(
router: HttpServer,
routeDefinitions: RouteDefinition[],
instanceWrapper: InstanceWrapper,
moduleKey: string,
routePathMetadata: RoutePathMetadata,
host: string | RegExp | Array<string | RegExp>,
) {
routeDefinitions.forEach(routeDefinition => {
this.applyCallbackToRouter(
router,
routeDefinition,
instanceWrapper,
moduleKey,
routePathMetadata,
host,
);
});
}
// 绑定处理函数
private applyCallbackToRouter(
router: HttpServer,
routeDefinition: RouteDefinition,
instanceWrapper: InstanceWrapper,
moduleKey: string,
routePathMetadata: RoutePathMetadata,
host: string | RegExp | Array<string | RegExp>,
) {
const { path, requestMethod, targetCallback, methodName } = routeDefinition;
// 创建执行上下文
const executionContext = this.executionContextCreator.create(
instanceWrapper,
targetCallback,
methodName,
moduleKey,
requestMethod,
);
// 创建代理处理函数
const proxy = this.createCallbackProxy(
instanceWrapper,
executionContext,
methodName,
moduleKey,
requestMethod,
);
// 构建完整路径
const fullPath = this.routePathFactory.create(routePathMetadata, requestMethod);
// 注册到路由器
this.routerMethodFactory
.get(router, requestMethod)
.call(router, fullPath, proxy);
this.logger.log(ROUTE_MAPPED_MESSAGE(fullPath, requestMethod));
}
}
RouterExecutionContext
创建路由执行上下文,组装完整的请求处理管道:
// packages/core/router/router-execution-context.ts
export class RouterExecutionContext {
public create(
instance: Controller,
callback: (...args: any[]) => unknown,
methodName: string,
moduleKey: string,
requestMethod: RequestMethod,
contextId = STATIC_CONTEXT,
inquirerId?: string,
) {
const contextType: ContextType = 'http';
// 获取元数据
const { argsLength, fnHandleResponse, paramtypes, getParamsMetadata, httpStatusCode, responseHeaders } =
this.getMetadata(instance, callback, methodName, moduleKey, requestMethod, contextType);
// 创建管道
const pipes = this.pipesContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
// 创建守卫
const guards = this.guardsContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
// 创建拦截器
const interceptors = this.interceptorsContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
// 创建守卫执行函数
const fnCanActivate = this.createGuardsFn(guards, instance, callback, contextType);
// 创建管道执行函数
const fnApplyPipes = this.createPipesFn(pipes, paramsOptions);
// 返回请求处理函数
return async <TRequest, TResponse>(req: TRequest, res: TResponse, next: Function) => {
const args = this.contextUtils.createNullArray(argsLength);
// 1. 执行守卫
fnCanActivate && (await fnCanActivate([req, res, next]));
// 2. 设置响应状态和头
this.responseController.setStatus(res, httpStatusCode);
hasCustomHeaders && this.responseController.setHeaders(res, responseHeaders);
// 3. 执行拦截器(包含管道和处理器)
const result = await this.interceptorsConsumer.intercept(
interceptors,
[req, res, next],
instance,
callback,
handler(args, req, res, next), // 内部执行管道和处理器
contextType,
);
// 4. 处理响应
await fnHandleResponse(result, res, req);
};
}
}
关键点:
- 按顺序创建 Guards、Interceptors、Pipes
- 守卫在拦截器之前执行
- 管道在路由处理器之前执行(在拦截器内部)
## 请求处理流程
Request ↓ ┌─────────────────────────────────────┐ │ 1. Guards (守卫) │ │ canActivate() → true/false │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 2. Interceptors (拦截器 - before) │ │ intercept() → Observable │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 3. Pipes (管道) │ │ transform() → value │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 4. Route Handler (路由处理器) │ │ controller.method() │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 5. Interceptors (拦截器 - after) │ │ Observable.pipe() │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 6. Exception Filters (异常过滤器) │ │ catch() → response │ └─────────────────────────────────────┘ ↓ Response
## GuardsConsumer
执行守卫:
```typescript
// packages/core/guards/guards-consumer.ts
export class GuardsConsumer {
public async tryActivate(
guards: CanActivate[],
args: unknown[],
instance: Controller,
callback: (...args: unknown[]) => unknown,
type?: string,
): Promise<boolean> {
if (!guards || isEmpty(guards)) {
return true;
}
const context = this.createContext(args, instance, callback);
context.setType(type);
// 依次执行守卫
for (const guard of guards) {
const result = guard.canActivate(context);
// 处理同步/异步/Observable 结果
if (typeof result === 'boolean') {
if (!result) return false;
continue;
}
if (await this.pickResult(result)) {
continue;
}
return false;
}
return true;
}
}
InterceptorsConsumer
执行拦截器:
// packages/core/interceptors/interceptors-consumer.ts
export class InterceptorsConsumer {
public async intercept(
interceptors: NestInterceptor[],
args: unknown[],
instance: Controller,
callback: (...args: unknown[]) => unknown,
next: () => Promise<unknown>,
type?: string,
): Promise<unknown> {
if (isEmpty(interceptors)) {
return next();
}
const context = this.createContext(args, instance, callback);
context.setType(type);
// 构建拦截器链
const nextFn = async (i = 0) => {
if (i >= interceptors.length) {
return defer(() => this.transformDeferred(next));
}
const handler: CallHandler = {
handle: () => defer(() => nextFn(i + 1)).pipe(mergeAll()),
};
return interceptors[i].intercept(context, handler);
};
return defer(() => nextFn()).pipe(mergeAll());
}
}
PipesConsumer
执行管道:
// packages/core/pipes/pipes-consumer.ts
export class PipesConsumer {
public async apply(
value: unknown,
{ metatype, type, data }: ArgumentMetadata,
pipes: PipeTransform[],
) {
return this.applyPipes(value, { metatype, type, data }, pipes);
}
public async applyPipes(
value: unknown,
metadata: { metatype: any; type?: any; data?: any },
transforms: PipeTransform[],
) {
// 依次执行管道
return transforms.reduce(async (deferredValue, pipe) => {
const val = await deferredValue;
const result = pipe.transform(val, metadata);
return result;
}, Promise.resolve(value));
}
}
参数解析
RouteParamsFactory
// packages/core/router/route-params-factory.ts
export class RouteParamsFactory {
public exchangeKeyForValue(
key: RouteParamtypes,
data: string | object | any,
{ req, res, next }: { req: any; res: any; next: Function },
) {
switch (key) {
case RouteParamtypes.REQUEST:
return req;
case RouteParamtypes.RESPONSE:
return res;
case RouteParamtypes.NEXT:
return next;
case RouteParamtypes.BODY:
return data ? req.body?.[data] : req.body;
case RouteParamtypes.PARAM:
return data ? req.params?.[data] : req.params;
case RouteParamtypes.QUERY:
return data ? req.query?.[data] : req.query;
case RouteParamtypes.HEADERS:
return data ? req.headers?.[data.toLowerCase()] : req.headers;
case RouteParamtypes.IP:
return req.ip;
case RouteParamtypes.HOST:
return req.hostname;
default:
return null;
}
}
}
异常处理
ExceptionsHandler
// packages/core/exceptions/exceptions-handler.ts
export class ExceptionsHandler {
public handle(
exception: Error | HttpException | any,
host: ArgumentsHost,
): void {
// 尝试使用自定义过滤器
for (const filter of this.filters) {
if (this.isExceptionOfType(exception, filter.exceptionMetatypes)) {
filter.func(exception, host);
return;
}
}
// 使用默认处理
this.invokeCustomFilters(exception, host);
}
}
版本控制
@Controller({
path: 'cats',
version: '1',
})
export class CatsControllerV1 {}
@Controller({
path: 'cats',
version: '2',
})
export class CatsControllerV2 {}
版本路由处理:
// packages/core/router/router-explorer.ts
private applyVersionFilter(
router: HttpServer,
routePathMetadata: RoutePathMetadata,
versioningOptions: VersioningOptions,
) {
const version = routePathMetadata.methodVersion;
if (versioningOptions.type === VersioningType.URI) {
// URI 版本:/v1/cats
return this.routePathFactory.create(routePathMetadata, requestMethod);
}
if (versioningOptions.type === VersioningType.HEADER) {
// Header 版本:X-API-Version: 1
return this.createVersionedHandler(version);
}
if (versioningOptions.type === VersioningType.MEDIA_TYPE) {
// Media Type 版本:Accept: application/json;v=1
return this.createMediaTypeVersionedHandler(version);
}
}
总结
NestJS 路由系统的核心:
- RoutesResolver:解析所有控制器的路由
- RouterExplorer:探索路由方法,注册到 HTTP 适配器
- RouterExecutionContext:创建执行上下文,组装管道
- 请求处理管道:Guards → Interceptors → Pipes → Handler → Interceptors → Filters
- 参数解析:RouteParamsFactory 解析 @Body、@Query 等
- 版本控制:支持 URI、Header、Media Type 三种方式
下一篇我们将分析中间件机制的实现。
📦 源码位置:
packages/core/router/下一篇:NestJS 中间件机制