nest - 使用自定义拦截器进行响应

标签 nest interceptor

我正在使用全局拦截器来获取如下响应:

{
  "data": "",
  "statusCode": int
  "message": "string"
}

所以我创建了拦截器文件

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

export interface Response<T> {
    data: T;
}

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

并将其放入我的main.ts

在我的 Controller 中我有:

  @Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    return await this.usersService.update(userId, userUpdate);    
  }

结果是:

{
  "data": {
    "_id": "621d07d9ea0cdc600fae0f02",    
    "username": "foo",
    "name": "stringwwww",
    "__v": 0
  },
  "statusCode": 201
}

如果我想添加我的自定义消息,我需要返回一个像这样的对象:

@Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    const result = await this.usersService.update(userId, userUpdate);    
    return { message: 'User updated', result };    
  }

但在那种情况下我有两次消息并且结构不正确:

{
  "data": {
    "message": "User updated",
    "result": {
      "_id": "621d07d9ea0cdc600fae0f02",
      "username": "foo",
      "name": "stringwwww",
      "__v": 0
    }
  },
  "statusCode": 201,
  "message": "User updated"
}

如何设置自定义(可选)消息?

I can modify my interceptors like:
@Injectable()
export class TransformationInterceptor<T> implements NestInterceptor<T, Response<T>> {
    intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
        return next.handle().pipe(map(data => ({ 
            data: data.res,
            statusCode: context.switchToHttp().getResponse().statusCode,
            message: data.message
        })));
    }
}

我的 Controller 是这样的:

@Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    const result = await this.usersService.update(userId, userUpdate);    
    return { message: 'User updated', res: result };    
  }

我会得到正确的表格,但我不想添加

return { message: 'User updated', res: result };    

对于每个 Controller

最佳答案

实现此目的的一种方法如下,但您将被绑定(bind)到每个 Controller 的固定消息

创建一个响应装饰器(response.decorator.ts)

import { SetMetadata } from '@nestjs/common'

export const ResponseMessageKey = 'ResponseMessageKey'
export const ResponseMessage = (message: string) => SetMetadata(ResponseMessageKey, message)

为您的响应创建常量文件 (response.constants.ts)

export const USER_INSERTED = 'User Inserted'
export const USER_UPDATED = 'User Updated'
export const USER_DELETED = 'User Deleted'

将装饰器添加到您的 Controller 以设置响应消息元数据

@Patch('/:userId')
@HttpCode(201)
@ResponseMessage(USER_UPDATED)
public async updateUser(    
  @Param('userId') userId: string,
  @Body() userUpdate: UpdateUserDto
): Promise<any> {      
  const result = await this.usersService.update(userId, userUpdate);    
  return result;    
}

更新您的拦截器以从 Controller 上设置的元数据中读取响应消息并将其添加到响应中

import { Reflector } from '@nestjs/core'

@Injectable()
export class TransformationInterceptor<T>
  implements NestInterceptor<T, Response<T>>
{
  constructor(private reflector: Reflector) {}

  intercept(
    context: ExecutionContext,
    next: CallHandler
  ): Observable<Response<T>> {
    const responseMessage = this.reflector.get<string>(
      ResponseMessageKey,
      context.getHandler()
    ) ?? ''

    return next.handle().pipe(
      map((data) => ({
        data,
        statusCode: context.switchToHttp().getResponse().statusCode,
        message: responseMessage
      }))
    )
  }
}

您可以扩展此方法以将字符串/对象列表设置为可能的响应(元数据),并根据拦截器中的响应代码,将特定消息发送为 response.message

关于nest - 使用自定义拦截器进行响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71342465/

相关文章:

elasticsearch - 创建索引 Nest

entity-framework - 如何使用 EF + lambda 表达式隐藏某些列(对于 WCF QueryInterceptor)

grails - 在 Grails/Groovy 中拦截或重命名方法调用

java - 如何在 jersey WriterInterceptor 实现中获取 @interface 参数

spring - 使用 Spring Boot 拦截器重定向

elasticsearch - ElasticSearch-从热门单词中过滤停用词

c# - Elasticsearch索引文档,但下一个查询返回0个匹配

javascript - 您如何在客户端(浏览器)AJAX 请求/响应对上实现拦截器模式?

c# - 嵌套具有字段优先级的查询和过滤查询

elasticsearch - NEST如何使用注释设置完成建议上下文