Files
tyapi-server/internal/infrastructure/external
2025-10-16 18:35:18 +08:00
..
2025-08-04 17:16:38 +08:00
2025-08-02 02:54:21 +08:00
2025-07-28 01:46:39 +08:00
2025-07-13 16:36:20 +08:00
new
2025-09-12 01:15:09 +08:00
new
2025-09-12 01:15:09 +08:00
2025-08-02 02:54:21 +08:00
fix
2025-09-30 12:03:51 +08:00
fix
2025-09-30 12:03:51 +08:00
new
2025-10-16 18:35:18 +08:00
fix
2025-08-27 22:19:19 +08:00
fix
2025-08-27 22:19:19 +08:00
fix
2025-08-27 22:19:19 +08:00

外部服务错误处理修复说明

问题描述

在外部服务WestDex、Yushan、Zhicha使用 fmt.Errorf("%w: %s", ErrXXX, err) 包装错误后,外层的 errors.Is(err, ErrXXX) 无法正确识别错误类型。

问题原因

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

修复方案

统一使用 errors.Join 来组合错误,这是 Go 1.20+ 的标准做法,天然支持 errors.Is 判断。

修复内容

1. WestDex 服务 (westdex_service.go)

修复前:

// 无法被 errors.Is 识别的错误包装
err = fmt.Errorf("%w: %s", ErrSystem, marshalErr.Error())
err = fmt.Errorf("%w: %s", ErrDatasource, westDexResp.Message)

修复后:

// 可以被 errors.Is 正确识别的错误组合
err = errors.Join(ErrSystem, marshalErr)
err = errors.Join(ErrDatasource, fmt.Errorf(westDexResp.Message))

2. Yushan 服务 (yushan_service.go)

修复前:

// 无法被 errors.Is 识别的错误包装
err = fmt.Errorf("%w: %s", ErrSystem, err.Error())
err = fmt.Errorf("%w: %s", ErrDatasource, "羽山请求retdata为空")

修复后:

// 可以被 errors.Is 正确识别的错误组合
err = errors.Join(ErrSystem, err)
err = errors.Join(ErrDatasource, fmt.Errorf("羽山请求retdata为空"))

3. Zhicha 服务 (zhicha_service.go)

修复前:

// 无法被 errors.Is 识别的错误包装
err = fmt.Errorf("%w: %s", ErrSystem, marshalErr.Error())
err = fmt.Errorf("%w: %s", ErrDatasource, "HTTP状态码 %d", response.StatusCode)

修复后:

// 可以被 errors.Is 正确识别的错误组合
err = errors.Join(ErrSystem, marshalErr)
err = errors.Join(ErrDatasource, fmt.Errorf("HTTP状态码 %d", response.StatusCode))

修复效果

修复前的问题:

// 在应用服务层
if errors.Is(err, westdex.ErrDatasource) {
    // 这里无法正确识别,因为 fmt.Errorf 包装的错误
    // 没有实现 Is() 接口
    return ErrDatasource
}

修复后的效果:

// 在应用服务层
if errors.Is(err, westdex.ErrDatasource) {
    // 现在可以正确识别了!
    return ErrDatasource
}

if errors.Is(err, westdex.ErrSystem) {
    // 系统错误也能正确识别
    return ErrSystem
}

优势

  1. 完全兼容errors.Is 现在可以正确识别所有错误类型
  2. 标准做法:使用 Go 1.20+ 的 errors.Join 标准库功能
  3. 性能优秀:标准库实现,性能优于自定义解决方案
  4. 维护简单:无需自定义错误类型,代码更简洁

注意事项

  1. Go版本要求:需要 Go 1.20 或更高版本(项目使用 Go 1.23.4,完全满足)
  2. 错误消息格式errors.Join 使用换行符分隔多个错误
  3. 向后兼容:现有的错误处理代码无需修改

测试验证

所有修复后的外部服务都能正确编译:

go build ./internal/infrastructure/external/westdex/...
go build ./internal/infrastructure/external/yushan/...
go build ./internal/infrastructure/external/zhicha/...

总结

通过统一使用 errors.Join 修复外部服务的错误处理,现在:

  • errors.Is(err, ErrDatasource) 可以正确识别数据源异常
  • errors.Is(err, ErrSystem) 可以正确识别系统异常
  • errors.Is(err, ErrNotFound) 可以正确识别查询为空
  • 错误处理逻辑更加清晰和可靠
  • 符合 Go 1.20+ 的最佳实践

这个修复确保了整个系统的错误处理链路都能正确工作,提高了系统的可靠性和可维护性。