Files
tyapi-server/internal/domains/api/services/processors/README.md
2025-08-27 22:19:19 +08:00

129 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 处理器错误处理解决方案
## 问题描述
在使用 `errors.Join(processors.ErrInvalidParam, err)` 包装错误后,外层的 `errors.Is(err, processors.ErrInvalidParam)` 无法正确识别错误类型。
## 原因分析
`fmt.Errorf` 创建的包装错误虽然实现了 `Unwrap()` 接口,但没有实现 `Is()` 接口,因此 `errors.Is` 无法正确判断错误类型。
## 解决方案
### 🎯 **推荐方案:使用 `errors.Join`Go 1.20+**
这是最简洁、最标准的解决方案Go 1.20+ 原生支持:
```go
// 在处理器中创建错误
return nil, errors.Join(processors.ErrInvalidParam, err)
// 在应用服务层判断错误
if errors.Is(err, processors.ErrInvalidParam) {
// 现在可以正确识别了!
businessError = ErrInvalidParam
return ErrInvalidParam
}
```
### ✅ **优势**
1. **极简代码**:一行代码解决问题
2. **标准库支持**Go 1.20+ 原生功能
3. **完全兼容**`errors.Is` 可以正确识别错误类型
4. **性能优秀**:标准库实现,性能最佳
5. **向后兼容**:现有的错误处理代码无需修改
### 📝 **使用方法**
#### 在处理器中(替换旧方式):
```go
// 旧方式 ❌
return nil, errors.Join(processors.ErrInvalidParam, err)
// 新方式 ✅
return nil, errors.Join(processors.ErrInvalidParam, err)
```
#### 在应用服务层(现在可以正确工作):
```go
if errors.Is(err, processors.ErrInvalidParam) {
// 现在可以正确识别了!
businessError = ErrInvalidParam
return ErrInvalidParam
}
```
## 其他方案对比
### 方案1`errors.Join`(推荐 ⭐⭐⭐⭐⭐)
- **简洁度**:⭐⭐⭐⭐⭐
- **兼容性**:⭐⭐⭐⭐⭐
- **性能**:⭐⭐⭐⭐⭐
- **维护性**:⭐⭐⭐⭐⭐
### 方案2自定义错误类型
- **简洁度**:⭐⭐⭐
- **兼容性**:⭐⭐⭐⭐⭐
- **性能**:⭐⭐⭐⭐
- **维护性**:⭐⭐⭐
### 方案3继续使用 `fmt.Errorf`
- **简洁度**:⭐⭐⭐⭐
- **兼容性**:❌(无法识别错误类型)
- **性能**:⭐⭐⭐⭐
- **维护性**:❌
## 迁移指南
### 步骤1: 检查Go版本
确保项目使用 Go 1.20 或更高版本
### 步骤2: 更新错误创建
将所有处理器中的 `fmt.Errorf("%s: %w", processors.ErrXXX, err)` 替换为 `errors.Join(processors.ErrXXX, err)`
### 步骤3: 验证错误判断
确保应用服务层的 `errors.Is(err, processors.ErrXXX)` 能正确工作
### 步骤4: 测试验证
运行测试确保所有错误处理逻辑正常工作
## 示例
```go
// 处理器层
func ProcessRequest(ctx context.Context, params []byte, deps *ProcessorDependencies) ([]byte, error) {
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// ... 其他逻辑
}
// 应用服务层
if err := s.apiRequestService.PreprocessRequestApi(ctx, cmd.ApiName, requestParams, &cmd.Options, callContext); err != nil {
if errors.Is(err, processors.ErrInvalidParam) {
// 现在可以正确识别了!
businessError = ErrInvalidParam
return ErrInvalidParam
}
// ... 其他错误处理
}
```
## 注意事项
1. **Go版本要求**:需要 Go 1.20 或更高版本
2. **错误消息格式**`errors.Join` 使用换行符分隔多个错误
3. **完全兼容**`errors.Is` 现在可以正确识别所有错误类型
4. **性能提升**:标准库实现,性能优于自定义解决方案
## 总结
使用 `errors.Join` 是最简洁、最标准的解决方案:
- ✅ 一行代码解决问题
- ✅ 完全兼容 `errors.Is`
- ✅ Go 1.20+ 原生支持
- ✅ 性能优秀,维护简单
如果你的项目使用 Go 1.20+,强烈推荐使用这个方案!