NestJS 响应处理
如何返回异常
NestJS中,若需要返回异常给客户端,可在 Controller
Service
中实现。
例如,现在需要提示客户端,HTTP CODE 400,并返回错误消息,以Controller
为例,实现如下:
import { BadRequestException, Controller, Get } from '@nestjs/common'; @Controller() export class AppController { @Get() getHello() { throw new BadRequestException('这是一个错误的请求(客户端异常)'); } }
客户端拿到的返回结果:
{ "message": "这是一个错误的请求(客户端异常)", "error": "Bad Request", "statusCode": 400 }
除BadRequestException
之外,NestJS也提供了很多异常响应类,可从@nestjs/common
导出。
下表罗列了NestJS提供的常用异常响应类,供大家参考:
方法名 | 状态码 | 解释 |
BadRequestException | 400 | 错误的请求(客户端的错误) |
UnauthorizedException | 401 | 没有权限 |
NotFoundException | 404 | 没有找到资源 |
ForbiddenException | 403 | 禁止访问 |
NotAcceptableException | 406 | 无法解析 |
RequestTimeoutException | 408 | 请求超时 |
ConflictException | 409 | 请求与服务器端目标资源的当前状态相冲突 |
GoneException | 410 | 该资源已经不再可用(永久) |
HttpVersionNotSupportedException | 505 | 不支持该http协议 |
PayloadTooLargeException | 413 | 实体数据过大 |
UnsupportedMediaTypeException | 415 | 格式不被支持 |
UnprocessableEntityException | 422 | 语义错误,无法响应 |
InternalServerErrorException | 500 | 服务器遇到意外的状况,无法完成对请求的处理 |
NotImplementedException | 501 | 服务器不支持当前请求所需要的某个功能 |
ImATeapotException | 418 | 彩蛋,也用于一些爬虫警告 |
MethodNotAllowedException | 405 | 请求方式错误 |
BadGatewayException | 502 | 网关错误 |
ServiceUnavailableException | 503 | 而无法处理请求,能会在一些延迟后得到缓解 |
GatewayTimeoutException | 504 | 网关超时 |
PreconditionFailedException | 412 | 未满足前提条件 |
自定义异常类
除了内置方法,NestJS还提供了自定义异常响应类,HttpException
,可从@nestjs/common
导入。
export declare class HttpException extends IntrinsicException { /** * @param response string, object describing the error condition or the error cause. * @param status HTTP response status code. * @param options An object used to add an error cause. */ constructor(response: string | Record<string, any>, status: number, options?: HttpExceptionOptions | undefined); }
从截取的HttpException
官方interface定义中,可以看到最常用的两个参数:response
、status
。
例如,我现在需要返回给一个内部约定状态码 810,并提示客户端,服务器仍在处理中。
import { HttpException, Controller, Get, HttpStatus } from '@nestjs/common'; @Controller() export class AppController { @Get() getHello(): string { throw new HttpException('服务器仍在处理中,请稍候重试', 810); } }
客户端拿到的返回结果:
{ "statusCode": 810, "message": "服务器仍在处理中,请稍候重试" }
假设该810响应类型,使用频率较高,可进一步使用HttpException
方法创建自定义异常类,方便统一维护使用。例:
创建 ProcessingException
自定义响应异常类,实现方式如下:
import { HttpException } from '@nestjs/common'; export class ProcessingException extends HttpException { public constructor(message: string = '服务器仍在处理中,请稍候重试') { super(message, 810); // 810 是内部业务约定状态码 } }
使用 ProcessingException
自定义异常类,与官方内置的异常类使用方法一致:
import { Controller, Get } from '@nestjs/common'; import { ProcessingException } from './processing.exception'; @Controller() export class AppController { @Get() getHello() { throw new ProcessingException(); } }
由此得出,HttpException
可实现自定义响应内容,也可以进一步封装成自定义异常类,统一维护,随处调用,方便维护。
包装响应体
业务开发中,常常会对客户端响应体进行包装,格式大致如下:
{ "code": 200, "content": "Hello World!", "message": "success", "timestamp": 1738809371994 }
若实现该响应体格式,需要对正常响应、异常响应,进行拦截包装。
1. 🚓 正常响应
// src/interceptor/http-success/http-success.interceptor.ts import { HttpStatus, Injectable, CallHandler, NestInterceptor, ExecutionContext, } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; export interface TypeHttpResponseContext<T> { content: T; } @Injectable() export class HttpSuccessInterceptor<T> implements NestInterceptor<T, TypeHttpResponseContext<T>> { intercept( context: ExecutionContext, next: CallHandler<T>, ): Observable<TypeHttpResponseContext<T>> { const response = context.switchToHttp().getResponse(); return next.handle().pipe( map((content) => { response.status(HttpStatus.OK); return { content, message: 'success', code: HttpStatus.OK, timestamp: new Date().valueOf(), }; }), ); } }
2. 👮 异常响应
// src/filter/http-exception/http-exception.filter.ts import { Catch, HttpStatus, HttpException, ArgumentsHost, ExceptionFilter, } from '@nestjs/common'; interface TypeResponseData { statusCode: number; message: unknown; error: number; } @Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter { public catch(exception: HttpException, host: ArgumentsHost): void { const status = exception.getResponse() as TypeResponseData; const message = typeof status === 'string' ? status : String(status.message); host.switchToHttp().getResponse().status(HttpStatus.OK).send({ code: exception.getStatus(), message, timestamp: new Date().valueOf(), }); } }
3. 🚀 注册使用
在NestJS中,注册使用对应的拦截、过滤器,有两种方式,一种在AppModule
进行注册。另一种是在main.ts
中直接注册。可根据实际需求自行选择。更推荐在main.ts
中实现,更加简洁。
在main.ts
中注册使用:
import { AppModule } from './app.module'; import { NestFactory } from '@nestjs/core'; import { HttpExceptionFilter } from './filter/http-exception/http-exception.filter'; import { HttpSuccessInterceptor } from './interceptor/http-success/http-success.interceptor'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new HttpExceptionFilter()); app.useGlobalInterceptors(new HttpSuccessInterceptor()); await app.listen(process.env.PORT ?? 3000); } bootstrap();
在AppModule
中注册使用:
import { Module } from '@nestjs/common'; import { AppService } from './app.service'; import { AppController } from './app.controller'; import { HttpExceptionFilter } from './filter/http-exception/http-exception.filter'; import { HttpSuccessInterceptor } from './interceptor/http-success/http-success.interceptor'; import { APP_INTERCEPTOR, APP_FILTER } from '@nestjs/core'; @Module({ imports: [], controllers: [AppController], providers: [ { provide: APP_FILTER, useClass: HttpExceptionFilter, }, { provide: APP_INTERCEPTOR, useClass: HttpSuccessInterceptor, }, AppService, ], }) export class AppModule {}
以上就是该文全部内容,主要参考了NestJS官方文档与自身开发实践,希望能够帮助到大家。