Go中判断错误是否临时应优先检查Temporary()方法,需通过类型断言安全调用;net.Error的Timeout()和Temporary()均true才真正可重试;context.DeadlineExceeded不可重试;自定义错误须显式实现Temporary()。
怎么判断一个 Go 错误是临时的还是永久的
Go 里没有统一的“临时错误”类型,但标准库用
和
等实现了
方法,这是最常见、最可靠的判断入口。别依赖错误字符串匹配或自定义字段,那容易漏判或误判。
实际场景中,临时错误多出现在网络连接、DNS 解析、I/O 超时等可重试环节;永久错误则是路径不存在、权限拒绝、协议不支持等无法靠重试解决的问题。
是最典型的临时错误接口,
和
都返回
才算真正可重试(比如
)
的
永远返回
,哪怕底层是
—— 它只表示路径层面失败,不反映连接状态
第三方库如
的
不实现
,但它也不是永久性故障,属于业务逻辑正常分支,别拿它当重试依据
为什么直接断言
方法会 panic
因为不是所有错误都实现了该方法。Go 的接口断言要求类型**明确实现**,而像
或
返回的错误值,压根没实现
,直接调用会触发 panic。
正确做法永远是类型断言 + 安全调用,而不是先假设存在再调用:
立即学习
“
go语言免费学习笔记(深入)
”;
注意:不要写成
—— 如果
不是
类型,这行就 panic。
算不算临时错误
不算。它是
包返回的不可恢复错误,类型是
或纯
,不实现
,也不应被重试。它代表调用方主动终止,不是底层系统暂时不可用。
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
常见混淆点:
和
中的
触发的
是两回事:后者可能包装了
,才可能临时
HTTP 请求超时若由底层 TCP 连接中断导致(如
),错误链里可能含
,这时才值得检查
单纯 context 超时,重试只会更快失败,还可能放大上游压力
自己封装错误时如何支持
如果你在写客户端库或封装底层调用,想让使用者能安全判断临时性,就让自定义错误类型显式实现
方法。别靠嵌套或转发——必须自己声明实现。
示例:
关键点:
不要把
实现成 “只要底层错误有这个方法就返回 true”,得结合语义:比如你封装的是幂等查询,即使底层报了
,你也可能选择不重试(因业务已保证最终一致)
如果错误来自
,建议透传其
结果;如果是新错误(如配置校验失败),一律返回
别在
里做耗时操作或加锁,它会被高频调用
临时错误判断真正难的不是语法,而是理解错误来源和重试边界——同一错误在不同上下文里,临时性可能完全不同。比如
在服务启动初期是临时的,在运维下线后就是永久的。代码只能告诉你“能重试”,不能替你决定“该不该重试”。
net.Erroros.PathErrorTemporary()net.ErrorTimeout()Temporary()truenet.OpErroros.PathErrorTemporary()falseENOTCONNdatabase/sqlsql.ErrNoRowsTemporary()Temporary()fmt.Errorf("xxx")errors.New("xxx")Temporary()if tempErr, ok := err.(interface{ Temporary() bool }); ok && tempErr.Temporary() {
// 可重试
}err.(net.Error).Temporary()errnet.Errorcontext.DeadlineExceededcontext*url.ErrorerrorTemporary()context.DeadlineExceedednet/httpClient.Timeoutnet/url.Errornet.OpErrorread: connection reset by peernet.OpErrorTemporary()Temporary()Temporary() booltype MyClientError struct {
Err error
IsTemp bool
}
func (e *MyClientError) Error() string { return e.Err.Error() }
func (e *MyClientError) Temporary() bool { return e.IsTemp }Temporary()Temporary()net.ErrorTemporary()falseTemporary()connection refused