如何在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
相关产品推荐
相关产品推荐

