You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Nest.js拦截器中访问上下文类的非静态服务属性?

解决NestJS拦截器中访问控制器关联服务的问题

你遇到的核心问题是:context.getClass() 获取到的是控制器的类构造函数,而非运行时的实例对象,所以只能访问静态成员,无法直接获取类中注入的非静态服务。下面提供两种可行的解决方案:

方案一:通过ModuleRef获取控制器实例

利用你已经注入的ModuleRef,可以获取到当前请求对应的控制器实例,进而访问实例中的服务依赖:

async intercept(
  context: ExecutionContext,
  next: CallHandler,
): Promise<Observable<any>> {
  const req = context.switchToHttp().getRequest();
  // 获取控制器类
  const controllerClass = context.getClass();
  // 获取控制器实例(支持单例/请求作用域)
  const controllerInstance = await this.moduleRef.resolve(controllerClass);

  // 假设控制器中注入了名为documentService的服务
  const targetService = controllerInstance.documentService;
  // 根据请求参数获取修改前的数据
  const originalData = await targetService.findOne(req.params.id);

  return next.handle().pipe(
    tap(async (responseData) => {
      // 结合原始数据与响应数据生成审计日志
      await this.auditlogService.create({
        method: req.method,
        originalData,
        modifiedData: responseData,
        // 补充其他审计字段
      });
    }),
  );
}

方案二:用元数据标记目标服务(更灵活)

如果不同控制器/方法需要调用不同的服务,可以自定义装饰器标记需要使用的服务,再通过Reflector读取元数据:

1. 定义自定义装饰器

import { SetMetadata } from '@nestjs/common';

export const AuditTargetService = (service: any) => SetMetadata('audit-target-service', service);

2. 在控制器方法上标记

@Put(':id')
@AuditTargetService(DocumentService)
async update(@Param('id') id: string, @Body() data: UpdateDto) {
  return this.documentService.update(id, data);
}

3. 在拦截器中获取并使用服务

async intercept(
  context: ExecutionContext,
  next: CallHandler,
): Promise<Observable<any>> {
  const req = context.switchToHttp().getRequest();
  // 读取元数据中的目标服务类型
  const targetServiceClass = this.reflector.get<any>(
    'audit-target-service',
    context.getHandler(),
  );
  // 获取服务实例
  const targetService = await this.moduleRef.resolve(targetServiceClass);

  const originalData = await targetService.findOne(req.params.id);

  return next.handle().pipe(
    tap(async (responseData) => {
      await this.auditlogService.create({
        method: req.method,
        originalData,
        modifiedData: responseData,
      });
    }),
  );
}

注意事项

  • 如果你的服务是请求作用域的,必须使用moduleRef.resolve()而非moduleRef.get(),前者会创建/获取当前请求上下文的实例。
  • 拦截器的tap操作符中使用async时,NestJS不会等待Promise完成,若需要确保审计日志写入完成后再返回响应,可以改用switchMap或mergeMap:
    return next.handle().pipe(
      switchMap(async (responseData) => {
        await this.auditlogService.create(/* 审计日志参数 */);
        return responseData;
      }),
    );
    

内容的提问来源于stack exchange,提问作者Afsal Kp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:13:31