处理器错误处理解决方案
问题描述
在使用 errors.Join(processors.ErrInvalidParam, err) 包装错误后,外层的 errors.Is(err, processors.ErrInvalidParam) 无法正确识别错误类型。
原因分析
fmt.Errorf 创建的包装错误虽然实现了 Unwrap() 接口,但没有实现 Is() 接口,因此 errors.Is 无法正确判断错误类型。
解决方案
🎯 推荐方案:使用 errors.Join(Go 1.20+)
这是最简洁、最标准的解决方案,Go 1.20+ 原生支持:
// 在处理器中创建错误
return nil, errors.Join(processors.ErrInvalidParam, err)
// 在应用服务层判断错误
if errors.Is(err, processors.ErrInvalidParam) {
// 现在可以正确识别了!
businessError = ErrInvalidParam
return ErrInvalidParam
}
✅ 优势
- 极简代码:一行代码解决问题
- 标准库支持:Go 1.20+ 原生功能
- 完全兼容:
errors.Is可以正确识别错误类型 - 性能优秀:标准库实现,性能最佳
- 向后兼容:现有的错误处理代码无需修改
📝 使用方法
在处理器中(替换旧方式):
// 旧方式 ❌
return nil, errors.Join(processors.ErrInvalidParam, err)
// 新方式 ✅
return nil, errors.Join(processors.ErrInvalidParam, err)
在应用服务层(现在可以正确工作):
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: 测试验证
运行测试确保所有错误处理逻辑正常工作
示例
// 处理器层
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
}
// ... 其他错误处理
}
注意事项
- Go版本要求:需要 Go 1.20 或更高版本
- 错误消息格式:
errors.Join使用换行符分隔多个错误 - 完全兼容:
errors.Is现在可以正确识别所有错误类型 - 性能提升:标准库实现,性能优于自定义解决方案
总结
使用 errors.Join 是最简洁、最标准的解决方案:
- ✅ 一行代码解决问题
- ✅ 完全兼容
errors.Is - ✅ Go 1.20+ 原生支持
- ✅ 性能优秀,维护简单
如果你的项目使用 Go 1.20+,强烈推荐使用这个方案!