Go 错误是值,需显式传递与上下文包装;跨包项目应分层处理、统一归一化错误,底层返回原始错误,上层用 errors.Wrap 或 xerrors 包装以携带调用链信息。
Go 语言本身没有异常机制,错误是值(error 接口),需显式传递和判断。在多模块(跨包)项目中,若各包自行定义错误、忽略上下文、不统一包装或丢失调用链,会导致错误排查困难、日志模糊、用户提示不友好。关键不是“捕获错误”,而是“携带上下文、分层处理、统一归一化”。
底层包(如 dal/)只返回原始错误(如数据库连接失败),上层包(如 service/)应包装错误,说明“在哪一步、为什么失败”。避免裸传 err。
示例:
// dal/user.go
func GetUserByID(id int) (*User, error) {
if id <= 0 {
return nil, errors.New("invalid user id")
}
// ... db query
if err != nil {
return nil, fmt.Errorf("query user from db: %w", err) // 使用 %w 包装
}
}
// service/user.go
func GetUser(ctx context.Context, id int) (*User, error) {
u, err := dal.GetUserByID(id)
if err != nil {
return nil, fmt.Errorf("failed to get user %d: %w", id, err) // 加业务语义
}
return u, nil
}
不建议所有错误都用 fmt.Errorf。可定义结构体错误,携带 Code(HTTP 状态码或业务码)、Message(用户可见)、Detail(调试用)、Meta(traceID、reqID 等)。
示例:
type AppError struct {
Code int `json:"code"`
Message string `json:"message"`
Detail string `json:"detail,omitempty"`
Meta map[string]string `json:"meta,omitempty"`
}
func (e *AppError) Error() string { return e.Message }
func (e *AppError) Unwrap() error { return nil } // 不包装其他 error,保持扁平
// 构造函数
func NewBadRequest(msg string) *AppError {
return &AppError{Code: http.StatusBadRequest, Message: msg}
}
func NewInternalErr(detail string) *AppError {
return &AppError{
Code: http.StatusInternalServerError,
Message: "服务暂时不可用",
Detail: detail,
Meta: map[string]string{"trace_id": trace.FromContext(context.TODO()).String()},
}
}
各包按职责返回对应类型的 *AppError,而非裸 error;中间层(如 handler)只负责转换为 HTTP 响应,不重新解释错误含义。
错误最终应在最外层被“终结”:记录完整堆栈(含 wrapped error)、返回用户友好的响应、必要时上报监控。不要在每个函数里 log.Printf。
errors.Is 判断是否为某类预设错误(如 os.IsNotExist、自定义 ErrNotFound)errors.As 提取具体错误类型(如提取 *AppError 获取 Code)fmt.Sprintf("%+v", err) 打印带堆栈的完整错误(需配合 xerrors 或 Go 1.13+ 的 %+v)示例(HTTP handler):
func UserHandler(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(r.URL.Query().Get("id"))
u, err := service.GetUser(r.Context(), id)
if err != nil {
// 记录详细错误(含所有 wrap 层)
log.
Error("user handler failed", "err", fmt.Sprintf("%+v", err), "req_id", middleware.ReqID(r))
var appErr *AppError
if errors.As(err, &appErr) {
render.JSON(w, appErr.Code, map[string]string{"message": appErr.Message})
} else {
render.JSON(w, http.StatusInternalServerError, map[string]string{"message": "系统错误"})
}
return
}
render.JSON(w, http.StatusOK, u)
}
err —— Go 不鼓励 panic 处理业务错误log.Println(err) —— 导致重复日志、无上下文、难以关联请求fmt.Errorf("xxx: %v", err) 当成包装 —— 丢失了 %w 的可展开能力,errors.Is 失效var ErrInvalid = errors.New("invalid"))未加包前缀,跨包易冲突
# go
# golang
# 为什么
# Error
# printf
# 全局变量
# 结构体
# 接口
# 栈
# 堆
# var
# 数据库
# http
# 都用
# 中间层
# 自定义
# 应在
# 而非
# 转换为
# 不可用
# 不重
# 判断是否
# 多模
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
网络优化76771 】
【
技术知识130152 】
【
IDC云计算60162 】
【
营销推广131313 】
【
AI优化88182 】
【
百度推广37138 】
【
网站推荐60173 】
【
精选阅读31334 】
相关推荐:
Mac如何整理桌面文件_Mac使用堆栈功能一键整理
Win11怎么开启自动HDR画质_Windows11显示设置HDR选项
如何有效拦截拼接式恶意域名的垃圾信息
c++协程和线程的区别 c++异步编程模型对比【核心】
win11如何清理传递优化文件 Win11为C盘瘦身删除更新缓存【技巧】
如何使用Golang实现云原生应用弹性伸缩_自动应对流量变化
如何在 Python 测试中动态配置 @backoff 装饰器的重试次数
Windows系统被恶意软件破坏后的恢复策略_错误提示修复方式
如何在JavaScript中动态拼接PHP的base_url与前端变量
Go 语言标准库为何不提供泛型切片的 Contains 方法?
如何使用Golang处理网络超时错误_Golang请求超时异常处理方法
如何在Golang中编写端到端测试_Golang E2E测试流程示例
Windows Defender扫描失败怎么办_安全模块损坏修复方式
Win10怎么卸载爱奇艺_Win10彻底卸载爱奇艺方法【步骤】
Win11怎么关闭搜索历史_Win11清除任务栏搜索记录【隐私】
Windows 10自带杀毒软件在哪_Windows 10打开和使用Windows安全中心
Windows 10怎么录屏_Windows 10使用Xbox Game Bar录制屏幕视频教程
php485在php5.6下能用吗_php485旧版本兼容性问题说明【详解】
Win11怎么查看硬盘型号_Windows 11检测硬盘信息方法【技巧】
Win11怎么设置虚拟内存最佳大小_Windows11性能选项自定义分页文件
Windows 11如何查看系统激活密钥_Windows 11使用CMD或PowerShell命令找回Product Key
Python文本编码与解码_跨平台解析说明【指导】
Win11怎么检查TPM2.0模块_Windows11受信任平台模块开启状态查询
Win11怎么关闭系统透明度_Windows11个性化颜色透明效果
php中self::能调用子类重写的方法吗_静态绑定与重写关系【介绍】
c++怎么用jemalloc c++替换默认内存分配器【性能】
Win11怎么关闭开机声音_Win11系统启动提示音静音【教程】
Windows10系统怎么查看IP地址_Win10网络连接状态详细信息
c++ reinterpret_cast怎么用 c++最危险的类型转换【详解】
Win11怎么关闭触摸屏_禁用Win11笔记本触摸屏功能设置【教程】
Python并发安全问题_资源竞争说明【指导】
Win11怎么恢复旧版开始菜单_通过软件还原Win10风格菜单【详解】
如何使用Golang管理跨项目依赖_Golang多模块项目依赖实践
c# F# 的 MailboxProcessor 和 C# 的 Actor 模型
如何使用Golang实现容器健康检查_监控和自动重启
Python实现图数据库操作_Neo4j核心CRUD与图算法解析
Win10怎样安装Word样式库_Win10安装Word样式教程【步骤】
Go语言中正确反序列化多个同级XML元素为结构体切片的方法
Linux如何挂载新硬盘_Linux磁盘分区格式化与开机自动挂载【指南】
Win11怎么开启上帝模式_创建Windows 11 God Mode全能文件夹【技巧】
c++中如何进行二进制文件读写_c++ read与write函数用法
Win11怎么设置环境变量_Win11配置Path路径变量【详解】
Win10电脑C盘红了怎么清理_Windows10系统盘深度瘦身指南
c++如何获取map中所有的键_C++遍历键值对提取所有key的方法
Win10怎样清理C盘浏览器缓存_Win10清理浏览器缓存步骤【步骤】
如何在 Python 中将 ISO 8601 时间戳转换为日期并计算日期差值
Win11关机快捷键是什么_Win11快速关机方法【大全】
Win11怎么关闭触控板_Win11笔记本禁用触摸板快捷键
Win11怎么关闭防火墙通知_屏蔽Win11安全中心安全警告弹窗【技巧】
Windows10如何更改桌面图标间距_Win10注册表WindowMetrics修改
2025-12-25
致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。