NestJS 入门(二)格式化响应数据及错误处理

前言

之前的章节,我们学习了如何用 NestJS 创建一个项目并连接数据库,并实现了一个对用户user的简单的 CRUD 接口。这一章我们将学习如何将返回的内容规范化。

情景

目前我们的接口返回数据杂乱无章,例如成功创建用户后接口返回了用户信息:

1
2
3
4
5
6
7
{
"username": "许平",
"password": "123456",
"id": 12,
"created_at": "2023-07-12T23:53:09.109Z",
"updated_at": "2023-07-12T23:53:09.109Z"
}

创建失败则会返回:

1
2
3
4
5
6
7
{
"message": [
"password should not be empty"
],
"error": "Bad Request",
"statusCode": 400
}

而我们希望我们返回的数据有着统一的格式,例如:

1
2
3
4
5
6
7
8
{
"code": 0,
"message": "请求成功",
"content": {
"access_token": "token",
"type": "Bearer"
}
}

code字段代表了请求的状态,0为成功,其他为失败,message则是操作的相关信息,content则是返回的请求的内容。

想实现这样的效果,需要先了解一些概念。

Interceptors 拦截器

拦截器(Interceptors)是在 Nest.js 框架中用于处理控制器方法的一种特殊类型组件。它们提供了一种在方法执行之前、之后或发生异常时进行拦截和操作的机制。

拦截器可以用于在方法执行前进行一些预处理操作,例如身份验证、权限检查、日志记录等。它们还可以在方法执行后对结果进行处理,例如格式化响应、数据转换等。此外,拦截器还可以捕获方法执行过程中的异常,并进行特定的处理或返回自定义的错误响应。

我们需要借用拦截器来对返回的数据进行格式化。

请求成功

首先我们用命令创建一个拦截器:

1
nest g interceptor global/interceptor/transform

编辑transform.interceptor.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, map } from 'rxjs';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map((data) => {
return {
code: 0,
message: '请求成功',
data,
};
}),
);
}
}

然后我们在main.ts中全局注册一下这个拦截器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { TransformInterceptor } from './global/interceptor/transform/transform.interceptor';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
app.useGlobalInterceptors(new TransformInterceptor())
await app.listen(3000);
}
bootstrap();

测试一下拦截器有没有创建成功:

1
curl --location --request GET 'http://localhost:3000/user/1'

响应为:

1
2
3
4
5
6
7
8
9
10
11
{
"code": 0,
"message": "请求成功",
"data": {
"id": 1,
"username": "孙明",
"password": "123456",
"created_at": "2023-07-12T23:53:01.321Z",
"updated_at": "2023-07-12T23:53:01.321Z"
}
}

Filter 过滤器

在 Nest.js 中,过滤器(Filters)是一种用于处理异常的特殊类型组件。它们允许您在应用程序中捕获和处理全局或特定路由处理程序中抛出的异常。

过滤器用于捕获控制器方法执行过程中可能出现的异常,并根据异常类型或其他条件执行相应的操作。它们可以用于处理和转换异常响应,返回自定义错误消息,记录日志,或执行其他适当的操作。

接下来我们通过过滤器来处理请求过程中的报错。

通过命令创建一个过滤器:

1
nest g filter global/filter/http-exception

编辑文件http-exception.filter.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { ArgumentsHost, Catch, ExceptionFilter, 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: Response = ctx.getResponse();
const status = exception.getStatus();

const message = exception.message ? exception.message :
status >= 500 ? 'Internal server error' : 'Bad request';
const errorResponse = {
code: status,
message,
content: {},
};

response.status(status);
response.header('Content-Type', 'application/json; charset=utf-8');
response.send(errorResponse);
}
}

然后我们在main.ts中全局注册这个过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { TransformInterceptor } from './global/interceptor/transform/transform.interceptor';
import { HttpExceptionFilter } from './global/filter/http-exception/http-exception.filter';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
app.useGlobalInterceptors(new TransformInterceptor());
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(3000);
}
bootstrap();

测试一下:

1
curl --location --request POST 'http://localhost:3000/user/' --data-urlencode 'username=段静'

响应结果:

1
2
3
4
5
{
"code": 400,
"message": "Bad Request Exception",
"content": {}
}

说明我们的错误过滤器已经成功应用了。

后记

笔者也是刚刚接触 Node ,目前还存在诸多不足,如果文章中有任何错误,欢迎在评论区批评指正。

Nest学习系列博客代码仓库 (github.com)

冷面杀手的个人站 (bald3r.wang)

NestJS 相关文章


NestJS 入门(二)格式化响应数据及错误处理
https://bald3r.wang/2023/07/14/NestJS-入门(二)格式化响应数据及错误处理/
作者
Allen
发布于
2023年7月14日
许可协议