Nest.js 内置 HTTP 异常笔记
一、核心概念
Nest.js 从 @nestjs/common 导出的所有内置 HTTP 异常均继承自 HttpException 基类,每个异常对应标准的 HTTP 状态码,用于在控制器/服务中快速抛出符合 RESTful 规范的错误响应,无需手动拼接状态码和响应格式。
二、完整内置异常列表(含状态码+使用场景)
| 异常类名 | HTTP 状态码 | 核心使用场景 |
|---|---|---|
| BadRequestException | 400 | 请求参数错误、格式非法(如参数校验失败) |
| UnauthorizedException | 401 | 未认证(如无 token、token 无效/过期) |
| NotFoundException | 404 | 资源不存在(如查询 ID 不存在的用户/文章) |
| ForbiddenException | 403 | 已认证但无权限操作(如普通用户访问管理员接口) |
| NotAcceptableException | 406 | 服务器无法生成客户端请求的内容格式(如客户端要求 XML 但仅支持 JSON) |
| RequestTimeoutException | 408 | 请求超时(如客户端请求未在指定时间内完成) |
| ConflictException | 409 | 资源冲突(如创建已存在的用户名、重复提交表单) |
| GoneException | 410 | 资源永久删除(如已下架的商品,无法恢复) |
| HttpVersionNotSupportedException | 505 | 不支持的 HTTP 协议版本(如客户端用 HTTP/3 但服务器仅支持 HTTP/1.1) |
| PayloadTooLargeException | 413 | 请求体过大(如上传文件超过服务器限制) |
| UnsupportedMediaTypeException | 415 | 不支持的媒体类型(如上传图片时 Content-Type 为 text/plain) |
| UnprocessableEntityException | 422 | 请求体格式正确但语义错误(如手机号格式正确但非合法号码) |
| InternalServerErrorException | 500 | 服务器内部错误(如代码逻辑异常、数据库连接失败) |
| NotImplementedException | 501 | 接口未实现(如规划中的接口暂未开发) |
| ImATeapotException | 418 | 趣味异常(RFC 2324 定义,实际极少使用,可用于测试) |
| MethodNotAllowedException | 405 | 请求方法不允许(如 GET 访问仅支持 POST 的接口) |
| BadGatewayException | 502 | 网关错误(如 Nest 作为网关转发请求时,后端服务返回无效响应) |
| ServiceUnavailableException | 503 | 服务不可用(如服务器维护、过载,暂时无法处理请求) |
| GatewayTimeoutException | 504 | 网关超时(如 Nest 转发请求时,后端服务响应超时) |
| PreconditionFailedException | 412 | 前置条件失败(如请求头中 If-Match 与服务器资源版本不匹配) |
三、基础使用方式
1. 最简使用(仅指定错误消息)
import { Controller, Get, NotFoundException } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string) {
const user = null; // 模拟查询不到用户
if (!user) {
// 仅指定消息,error 字段会默认显示 HTTP 状态码对应的默认描述(如 "Not Found")
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
}响应结果:
{
"message": "User with ID 123 not found",
"error": "Not Found",
"statusCode": 404
}2. 完整使用(指定消息+原因+描述)
import { Controller, Post, BadRequestException } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Post()
create(@Body() createUserDto: any) {
try {
// 模拟参数校验失败
if (!createUserDto.username) {
throw new Error('Username is required');
}
} catch (error) {
throw new BadRequestException('Failed to create user', {
cause: error, // 原始错误(用于日志排查,不会返回给客户端)
description: 'Username is a mandatory field', // 客户端可见的详细描述
});
}
}
}响应结果:
{
"message": "Failed to create user",
"error": "Username is a mandatory field",
"statusCode": 400
}四、进阶用法:自定义 HTTP 异常
若内置异常无法满足需求(如自定义状态码/响应格式),可继承 HttpException 实现自定义异常:
import { HttpException, HttpStatus } from '@nestjs/common';
// 自定义异常:请求频率过高(429 状态码)
export class TooManyRequestsException extends HttpException {
constructor(message: string = 'Too many requests', description?: string) {
super(
{
message,
error: description || 'Too Many Requests',
statusCode: HttpStatus.TOO_MANY_REQUESTS, // 429
},
HttpStatus.TOO_MANY_REQUESTS,
);
}
}
// 使用自定义异常
@Controller('api')
export class ApiController {
@Get()
getData() {
throw new TooManyRequestsException('请求过于频繁', '请等待 60 秒后重试');
}
}响应结果:
{
"message": "请求过于频繁",
"error": "请等待 60 秒后重试",
"statusCode": 429
}五、全局异常过滤器(统一响应格式)
实际开发中,通常会自定义全局异常过滤器,统一所有 HTTP 异常的响应格式(如增加 timestamp 字段):
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const exceptionResponse = exception.getResponse() as { message: string; error: string };
response.status(status).json({
code: status, // 自定义码段
msg: exceptionResponse.message,
detail: exceptionResponse.error,
timestamp: new Date().toISOString(), // 错误时间
path: ctx.getRequest().url, // 请求路径
});
}
}
// 在 main.ts 注册全局过滤器
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './filters/http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter()); // 全局生效
await app.listen(3000);
}
bootstrap();统一后的响应示例:
{
"code": 400,
"msg": "Something bad happened",
"detail": "Some error description",
"timestamp": "2026-02-24T10:00:00.000Z",
"path": "/users"
}总结
- Nest 内置 HTTP 异常覆盖了所有常见 HTTP 状态码,每个异常对应明确的业务场景,可直接抛出无需手动处理状态码;
- 内置异常支持自定义
message、cause(日志用)和description(客户端可见),兼顾排查和用户体验; - 若内置异常不满足需求,可继承
HttpException实现自定义异常,或通过全局过滤器统一响应格式。
评论