Files
tyapi-server/internal/domains/api/services/processors
2025-09-20 23:29:49 +08:00
..
new
2025-09-20 23:29:49 +08:00
fix
2025-08-27 22:19:19 +08:00
fix
2025-08-27 22:19:19 +08:00
2025-09-17 19:02:50 +08:00
fix
2025-08-27 22:19:19 +08:00
fix
2025-08-27 22:19:19 +08:00
new
2025-09-20 23:29:49 +08:00
2025-09-01 18:29:59 +08:00
2025-09-01 18:29:59 +08:00
fix
2025-08-27 22:19:19 +08:00
2025-07-28 01:46:39 +08:00
fix
2025-08-27 22:19:19 +08:00

处理器错误处理解决方案

问题描述

在使用 errors.Join(processors.ErrInvalidParam, err) 包装错误后,外层的 errors.Is(err, processors.ErrInvalidParam) 无法正确识别错误类型。

原因分析

fmt.Errorf 创建的包装错误虽然实现了 Unwrap() 接口,但没有实现 Is() 接口,因此 errors.Is 无法正确判断错误类型。

解决方案

🎯 推荐方案:使用 errors.JoinGo 1.20+

这是最简洁、最标准的解决方案Go 1.20+ 原生支持:

// 在处理器中创建错误
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. 向后兼容:现有的错误处理代码无需修改

📝 使用方法

在处理器中(替换旧方式):

// 旧方式 ❌
return nil, errors.Join(processors.ErrInvalidParam, err)

// 新方式 ✅  
return nil, errors.Join(processors.ErrInvalidParam, err)

在应用服务层(现在可以正确工作):

if errors.Is(err, processors.ErrInvalidParam) {
    // 现在可以正确识别了!
    businessError = ErrInvalidParam
    return ErrInvalidParam
}

其他方案对比

方案1errors.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
    }
    // ... 其他错误处理
}

注意事项

  1. Go版本要求:需要 Go 1.20 或更高版本
  2. 错误消息格式errors.Join 使用换行符分隔多个错误
  3. 完全兼容errors.Is 现在可以正确识别所有错误类型
  4. 性能提升:标准库实现,性能优于自定义解决方案

总结

使用 errors.Join 是最简洁、最标准的解决方案:

  • 一行代码解决问题
  • 完全兼容 errors.Is
  • Go 1.20+ 原生支持
  • 性能优秀,维护简单

如果你的项目使用 Go 1.20+,强烈推荐使用这个方案!