如何在NestJS自定义装饰器中获取控制器函数的响应?
如何在NestJS中获取控制器的响应数据用于缓存?
首先要明确:你当前用的参数装饰器是在控制器方法执行前被调用的,这时候控制器还没生成响应数据,所以根本拿不到最终的返回结果。要获取响应数据,应该用NestJS的拦截器——它能在请求生命周期的响应阶段介入,直接拿到控制器返回的结果。
问题代码回顾
你的参数装饰器代码
import { createParamDecorator, ExecutionContext } from "@nestjs/common"; export const CacheData = createParamDecorator( (data: any, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); console.log(request.url, request.method, 'request'); const response = ctx.switchToHttp().getResponse(); const reqBody = request.body; console.log(reqBody, 'reqBody'); console.log(response.raw.req.data, 'response'); console.log(response.raw.req.body, 'response'); console.log(response.raw.data, 'response'); console.log(response.cacheData, 'response'); } );
控制器使用代码
getStringsArr( @Headers('Authorization') auth: string, @Headers('Country') country = 'DK', @CacheData() cacheData, ): Array<string> { return ['Hello', 'World', '!']; }
解决方案:用拦截器获取响应数据
拦截器可以通过CallHandler的handle()方法捕获控制器返回的响应流,在响应发送前处理数据。下面是适配你需求的缓存拦截器实现:
1. 创建缓存拦截器
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class CacheInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); // 先记录请求信息,和你之前的逻辑一致 console.log(`${request.url} ${request.method} request`); console.log(request.body, 'reqBody'); // 执行控制器方法,监听响应流 return next.handle().pipe( tap((responseData) => { // 这里拿到的就是控制器返回的完整响应数据 console.log(responseData, 'response data'); // 在这里写你的缓存逻辑,比如把数据存入Redis或内存缓存 // 示例:cache.set(`${request.method}:${request.url}`, responseData); }), ); } }
2. 在控制器中使用拦截器
可以针对单个方法注册,也可以全局注册:
方法级使用
import { UseInterceptors } from '@nestjs/common'; // ... @UseInterceptors(CacheInterceptor) getStringsArr( @Headers('Authorization') auth: string, @Headers('Country') country = 'DK', ): Array<string> { return ['Hello', 'World', '!']; }
全局注册(可选)
如果所有路由都需要缓存逻辑,在AppModule中全局注册:
import { Module } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { CacheInterceptor } from './cache.interceptor'; @Module({ providers: [ { provide: APP_INTERCEPTOR, useClass: CacheInterceptor, }, ], }) export class AppModule {}
为什么参数装饰器拿不到响应?
NestJS参数装饰器的执行时机是控制器方法调用前,此时控制器还没执行,自然不会生成响应数据。而拦截器的tap操作符会在控制器返回响应后触发,刚好能拿到最终的响应结果。
内容的提问来源于stack exchange,提问作者Mahmoud Hadad
相关产品推荐
相关产品推荐

