NestJS响应拦截器应用

在NestJS中使用响应拦截器时遇到几个问题:

  1. 如何正确注册全局响应拦截器?我尝试在main.ts中使用useGlobalInterceptors但似乎不生效
  2. 响应拦截器中如何统一处理异常情况?目前我的拦截器会正常返回成功响应,但遇到异常时格式不一致
  3. 想给所有成功响应添加统一的timestamp和status字段,但发现部分第三方接口的响应结构被破坏了
  4. 如何根据不同的controller或路由动态调整响应格式?比如/admin和/api需要不同的包装格式
  5. 拦截器中对response数据进行修改时,有没有推荐的最佳实践?直接修改原始对象似乎有副作用
3 回复

在NestJS中,响应拦截器可以用于统一处理响应数据、添加日志、格式化输出等。例如,你可以创建一个全局的响应拦截器来为所有接口增加“success”字段。

  1. 创建拦截器:使用nest generate interceptor response命令生成response.interceptor.ts
  2. 在拦截器中实现逻辑,比如:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class ResponseInterceptor<T> implements NestInterceptor<T, { success: boolean; data: T }> {
  intercept(context: ExecutionContext, next: CallHandler): Observable<{ success: boolean; data: T }> {
    return next.handle().pipe(
      map(data => ({
        success: true,
        data,
      })),
    );
  }
}
  1. 注册拦截器:在app.module.ts中使用app.useGlobalInterceptors注册。
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { ResponseInterceptor } from './response.interceptor';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseInterceptor,
    },
  ],
})
export class AppModule {}

这样,所有接口返回的数据都会被拦截并加上success: true字段。


在NestJS中,响应拦截器可以用于统一处理所有响应数据,比如添加公共字段、日志记录或格式化输出。首先,创建一个拦截器类实现 nest/httpInjectablenest/coreNestInterceptor 接口。

例如,创建一个 LoggingInterceptor 来记录请求和响应时间:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const start = Date.now();
    return next.handle().pipe(
      tap(() => {
        const response = context.switchToHttp().getResponse();
        const delta = Date.now() - start;
        console.log(`${response.statusCode} ${context.getClass().name} ${context.getHandler().name} ${delta}ms`);
      }),
    );
  }
}

然后,在模块的 providers 中注册拦截器:

import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } } from './logging.interceptor';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor,
    },
  ],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {}
}

这样,所有接口都会经过这个拦截器,从而实现统一的日志记录功能。

在NestJS中,响应拦截器(Interceptor)允许你在方法执行前后添加额外的逻辑,常用于统一处理响应格式、日志记录等场景。下面是一个完整的响应拦截器实现示例:

import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
  intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
    return next.handle().pipe(
      map((data) => ({
        statusCode: context.switchToHttp().getResponse().statusCode,
        timestamp: new Date().toISOString(),
        data,
      })),
    );
  }
}

interface Response<T> {
  statusCode: number;
  timestamp: string;
  data: T;
}

应用拦截器有三种方式:

  1. 全局应用(在main.ts中):
app.useGlobalInterceptors(new TransformInterceptor());
  1. 控制器级别应用:
@Controller('cats')
@UseInterceptors(TransformInterceptor)
export class CatsController {}
  1. 方法级别应用:
@Get()
@UseInterceptors(TransformInterceptor)
findAll() {
  return this.catsService.findAll();
}

拦截器常见用途:

  • 统一响应格式
  • 添加响应头
  • 记录响应时间
  • 数据转换/净化

注意:当使用app.useGlobalInterceptors()时,拦截器不会注入依赖,如需依赖注入请使用模块注册方式。

回到顶部