我正在尝试为审计日志创建一个拦截器。如果请求是 PUT 或 PATCH,我想在这里获取以前的数据,所以我想在我的应用程序中访问不同的服务以在处理之前获取文档。
问题是我试图在拦截器中访问上下文类来获取与上下文类关联的服务,但是无法访问该服务。我可以访问静态变量,无论如何可以使用
getContext()
访问非静态成员,例如拦截器内的服务?
@Injectable()
export class AuditLoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger(AuditLoggingInterceptor.name);
constructor(
private readonly auditlogService: AuditLogService,
private readonly reflector: Reflector,
private readonly moduleRef: ModuleRef,
) {}
async intercept(
context: ExecutionContext,
next: CallHandler,
): Promise<Observable<any>> {
const req = context?.switchToHttp()?.getRequest();
const res = context?.switchToHttp()?.getResponse();
const ctx: any = context.getClass();
console.log(ctx, ctx.prototype, ctx.test, 'testing');
console.log(ctx.chec );
// how to access service inside class?
return next.handle().pipe(
tap(async (data) => {
return data;
}),
);
}
}
据我所知,如果控制器中的服务是
private
,您将无法直接访问它(如果它是公共的,您可以使用ModuleRef.get(controller).service
),但您可以使用一些巧妙的技巧和反射来获得什么您正在寻找。我能够设计一个非类型安全的示例,应该对其进行黑客攻击以使其更稳定,但我的想法是从控制器获取design:paramtypes
元数据,它应该是注入的提供者,然后找到类与当前控制器有相同的前缀加上Service
后缀,然后使用ModuleRef
从DI容器中抓取它。
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { ModuleRef, Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
@Injectable()
export class AppInterceptor implements NestInterceptor {
constructor(
private readonly moduleRef: ModuleRef,
private readonly reflector: Reflector,
) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const featureName = context.getClass().name.replace('Controller', '');
const controllerDeps = Reflect.getMetadata(
'design:paramtypes',
context.getClass(),
);
const serviceRef = controllerDeps.find((dep) => {
return dep.name?.match(featureName + 'Service');
});
const service = this.moduleRef.get(serviceRef, { strict: false });
console.log(service.getHello());
return next.handle();
}
}
我用一个简单的
nest new
项目和AppController
和AppService
做到了这一点,但这个想法应该扩展到你需要的任何东西。请确保为此添加类型安全,并仅在必要时使用它。