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

如何在Nest控制器中使用装饰器返回404状态码?

用NestJS自定义装饰器优雅解决实体不存在返回404的问题

嘿,太巧了!我最近在NestJS项目里也碰到了一模一样的场景——这个框架确实够好用,但默认返回undefined确实不够友好。用装饰器来实现404返回完全是正确的思路,既优雅又能复用,下面给你具体的实现方案:

第一步:编写自定义装饰器

我们可以创建一个装饰器,自动检查控制器方法的返回值。如果返回null或undefined,就抛出NestJS内置的NotFoundException(它会自动映射成HTTP 404状态码)。

import { NotFoundException } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export function NotFoundIfNull() {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    // 处理异步方法(Promise类型返回值)
    descriptor.value = async function (...args: any[]) {
      const result = await originalMethod.apply(this, args);
      if (result == null) { // 同时判断null和undefined
        throw new NotFoundException('请求的实体不存在');
      }
      return result;
    };

    // 兼容Observable类型返回值(比如使用RxJS的场景)
    if (!(descriptor.value instanceof AsyncFunction)) {
      descriptor.value = function (...args: any[]) {
        const result = originalMethod.apply(this, args);
        if (result instanceof Observable) {
          return result.pipe(
            map(data => {
              if (data == null) {
                throw new NotFoundException('请求的实体不存在');
              }
              return data;
            })
          );
        }
        if (result == null) {
          throw new NotFoundException('请求的实体不存在');
        }
        return result;
      };
    }

    return descriptor;
  };
}

第二步:在控制器中使用装饰器

现在只需要把这个装饰器加到你的findOneById方法上就行,注意修正原代码里的小细节(调用service要加this):

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get(':id')
  @NotFoundIfNull() // 就是这一行!
  async findOneById(@Param() params): Promise<User> {
    return this.userService.findOneById(params.id);
  }
}

额外说明

  • 你可以自定义404的错误信息,比如把NotFoundException的参数改成new NotFoundException('用户不存在'),这样返回的错误响应会更明确。
  • 这个装饰器可以复用在所有需要检查实体是否存在的控制器方法上,比如findOneByEmail、findOneByUsername等等,不用重复写判断逻辑。
  • 如果你的项目里大量用到这种场景,还可以把装饰器封装成一个公共模块,方便各个业务模块引入使用。

内容的提问来源于stack exchange,提问作者Rich Duncan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:49:36