177 lines
4.5 KiB
Markdown
177 lines
4.5 KiB
Markdown
|
|
# API调用错误处理规范
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
本文档定义了API调用接口的统一错误处理规范,包括错误码定义、响应结构、错误处理流程等。
|
|||
|
|
|
|||
|
|
## 响应结构
|
|||
|
|
|
|||
|
|
### 成功响应
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 0,
|
|||
|
|
"message": "业务成功",
|
|||
|
|
"transaction_id": "api_call_123456",
|
|||
|
|
"data": "加密的响应数据"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 错误响应
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 1001,
|
|||
|
|
"message": "接口异常",
|
|||
|
|
"transaction_id": "api_call_123456"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 错误码定义
|
|||
|
|
|
|||
|
|
| 错误码 | 错误类型 | 说明 |
|
|||
|
|
|--------|----------|------|
|
|||
|
|
| 0 | 业务成功 | 调用成功 |
|
|||
|
|
| 1000 | 查询为空 | 查询结果为空 |
|
|||
|
|
| 1001 | 接口异常 | 系统异常、数据源异常等 |
|
|||
|
|
| 1002 | 参数解密失败 | 请求参数解密失败 |
|
|||
|
|
| 1003 | 基础参数校验不正确 | 请求参数格式错误 |
|
|||
|
|
| 1004 | 未经授权的IP | IP不在白名单内 |
|
|||
|
|
| 1005 | 缺少Access-Id | 请求头中缺少Access-Id |
|
|||
|
|
| 1006 | 未经授权的AccessId | AccessId无效或账户已冻结 |
|
|||
|
|
| 1007 | 账户余额不足,无法请求 | 钱包余额不足 |
|
|||
|
|
| 1008 | 未开通此产品 | 产品不存在、已停用或未订阅 |
|
|||
|
|
| 2001 | 业务失败 | 第三方API业务逻辑失败 |
|
|||
|
|
|
|||
|
|
## 实现架构
|
|||
|
|
|
|||
|
|
### 1. 错误类型定义
|
|||
|
|
- 位置:`internal/application/api/errors.go`
|
|||
|
|
- 功能:定义具体的错误类型常量和错误码映射
|
|||
|
|
|
|||
|
|
### 2. 响应结构定义
|
|||
|
|
- 位置:`internal/application/api/dto/api_response.go`
|
|||
|
|
- 功能:定义统一的响应结构体和工厂方法
|
|||
|
|
|
|||
|
|
### 3. 应用层错误处理
|
|||
|
|
- 位置:`internal/application/api/api_application_service.go`
|
|||
|
|
- 功能:在业务逻辑中返回具体的错误类型
|
|||
|
|
|
|||
|
|
### 4. Handler层统一处理
|
|||
|
|
- 位置:`internal/infrastructure/http/handlers/api_handler.go`
|
|||
|
|
- 功能:根据错误类型返回对应的错误码和响应
|
|||
|
|
|
|||
|
|
## 错误处理流程
|
|||
|
|
|
|||
|
|
### 1. 基础参数校验(Handler层)
|
|||
|
|
```go
|
|||
|
|
// 检查Access-Id
|
|||
|
|
accessId := c.GetHeader("Access-Id")
|
|||
|
|
if accessId == "" {
|
|||
|
|
response := dto.NewErrorResponse(1005, "缺少Access-Id", "")
|
|||
|
|
c.JSON(400, response)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 参数绑定和校验
|
|||
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
|||
|
|
response := dto.NewErrorResponse(1003, "基础参数校验不正确", "")
|
|||
|
|
c.JSON(400, response)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 业务逻辑错误处理(应用层)
|
|||
|
|
```go
|
|||
|
|
// 用户不存在
|
|||
|
|
if err != nil {
|
|||
|
|
return ErrInvalidAccessId
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 账户已冻结
|
|||
|
|
if apiUser.IsFrozen() {
|
|||
|
|
return ErrFrozenAccount
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IP不在白名单
|
|||
|
|
if !apiUser.IsWhiteListed(cmd.ClientIP) {
|
|||
|
|
return ErrInvalidIP
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 统一错误响应(Handler层)
|
|||
|
|
```go
|
|||
|
|
// 调用应用服务
|
|||
|
|
transactionId, encryptedResp, err := h.appService.CallApi(c.Request.Context(), &cmd)
|
|||
|
|
if err != nil {
|
|||
|
|
// 根据错误类型返回对应的错误码
|
|||
|
|
errorCode := api.GetErrorCode(err)
|
|||
|
|
response := dto.NewErrorResponse(errorCode, err.Error(), transactionId)
|
|||
|
|
c.JSON(200, response) // API调用接口统一返回200状态码
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 中间件简化
|
|||
|
|
|
|||
|
|
原来的API认证中间件已经简化,只保留IP获取功能:
|
|||
|
|
- 认证逻辑移到Handler层处理
|
|||
|
|
- 保持中间件职责单一
|
|||
|
|
- 便于错误码的统一管理
|
|||
|
|
|
|||
|
|
## 测试
|
|||
|
|
|
|||
|
|
错误处理逻辑包含完整的单元测试:
|
|||
|
|
```bash
|
|||
|
|
go test ./internal/application/api -v
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 使用示例
|
|||
|
|
|
|||
|
|
### 成功调用
|
|||
|
|
```bash
|
|||
|
|
curl -X POST "http://localhost:8080/api/v1/test_api" \
|
|||
|
|
-H "Access-Id: your_access_id" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"data": "encrypted_request_data"}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
响应:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 0,
|
|||
|
|
"message": "业务成功",
|
|||
|
|
"transaction_id": "api_call_123456",
|
|||
|
|
"data": "encrypted_response_data"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 错误调用示例
|
|||
|
|
```bash
|
|||
|
|
# 缺少Access-Id
|
|||
|
|
curl -X POST "http://localhost:8080/api/v1/test_api" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"data": "encrypted_request_data"}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
响应:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 1005,
|
|||
|
|
"message": "缺少Access-Id",
|
|||
|
|
"transaction_id": ""
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 扩展说明
|
|||
|
|
|
|||
|
|
1. **新增错误类型**:在`errors.go`中添加新的错误常量和错误码映射
|
|||
|
|
2. **错误码调整**:修改`ErrorCodeMap`中的映射关系
|
|||
|
|
3. **响应结构扩展**:在`api_response.go`中添加新的响应字段或方法
|
|||
|
|
4. **国际化支持**:可以在错误消息中添加多语言支持
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
1. API调用接口统一返回HTTP 200状态码,错误通过响应体中的code字段区分
|
|||
|
|
2. 所有错误响应都包含transaction_id,便于问题追踪
|
|||
|
|
3. 错误消息使用中文,符合项目规范
|
|||
|
|
4. 错误处理遵循DDD分层架构,错误类型定义在应用层
|
|||
|
|
5. 错误码严格按照规范定义,不能多不能少
|