API
错误处理是软件开发的一个重要方面,包括 API
设计和实现。它涉及捕获和处理 API
请求处理过程中引发的错误,并将其转换为适当且有意义的 HTTP
响应,然后发送回客户端。
这是 API
开发中常见的做法,因为它为 API
的使用者提供了一致且用户友好的体验。它确保客户端始终收到信息丰富且可操作的错误响应,而不是通用错误消息。
精心设计的 API 错误处理有助于提高 API 的稳定性、安全性和可用性。
为了说明错误处理的重要性及其解决的问题,让我们看看一个简单的express
示例。
const express = require('express');
const app = express();
// ...
app.get('/users/:id', async (req, res) => {
const { id } = req.params;
const user = await getUserById(id);
if (!user) {
res.status(404).json({ error: 'User not found' });
} else {
res.json(user);
}
});
// ...
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
这段代码展示了错误处理背后的想法。它基本上说:如果找到用户,则返回 200 HTTP
代码,如果没有,则返回带有状态代码 404
的错误消息。
但是,当我们开始处理大量请求以及可能出现的不同错误情况时,这种处理控制器内部错误的方法开始变得越来越困难,特别是在标准化.。这时候错误处理策略就派上用场了。
虽然 Express
有解决这个问题的方法,但我们在这里将重点讨论 NestJs
如何解决它以及我们如何利用它。
Nest
带有内置的异常处理机制。这意味着每次 API
中抛出异常时,Nest
都会自动捕获它并转换为对客户端的良好响应。
import { Controller, Get, Param } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get(':id')
async getUser(@Param('id') id: string) {
return this.userService.getUser(id);
}
}
import { Injectable, NotFoundException } from '@nestjs/common';
import { UserRepository } from './user.repository';
import { User } from './user.entity';
@Injectable()
export class UserService {
constructor(private readonly userRepository: UserRepository) {}
async getUser(id: string): Promise<User> {
const user = await this.userRepository.findOne(id);
if (!user) {
throw new NotFoundException('User not found');
}
return user;
}
}
请注意,错误可能会在服务内部抛出,Nest
将负责捕获该错误并指定将发送到客户端的响应。在这种情况下,我们不需要指定控制器如何根据服务的行为进行操作,它只负责接收 HTTP
请求并将其路由到适当的服务。
如果找不到用户,客户端将收到类似以下内容的信息:
{
"statusCode": 404,
"message": "User not found",
"error": "Not Found"
}
NestJS
异常过滤器是允许您拦截和处理应用程序中引发的异常的组件。它们提供了一种将异常转换为特定响应或根据异常的类型或上下文执行自定义操作的机制。
当 Nest
捕获异常时,我们将使用此解决方案自定义我们的响应。提供的示例是一个简单的用例,我们可以根据自己的情况添加更多逻辑。
这样做实际上非常简单。首先我们创建一个`http-exception.filter.ts``文件:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, 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 request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
message: exception.message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
分解一下:
HttpException
类型的异常。HttpException
类型的异常时,将执行此过滤器的catch()
方法。catch()
方法内部,我们从异常和请求对象中提取必要的信息。response.status()
来设置响应中的 HTTP
状态码。它构建一个 JSON
响应,其中包含我发现与客户端相关的属性,并且可以根据自己的需要进行更改。response.json()
方法将响应发送到客户端。最后,我们需要通过将以下内容添加到main.ts
文件中来告诉 Nest
应用程序使用此过滤器:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// ...
// add the following line
app.useGlobalFilters(new HttpExceptionFilter());
// ...
await app.listen(configService.get('app.port') || 8080);
}
bootstrap();
现在,每当应用程序中抛出HttpException
异常时,客户端都会收到带有相关错误详细信息的 JSON
响应,包括状态代码、消息、时间戳和请求路径。这允许在整个应用程序中实现一致且标准化的错误处理和响应格式。