Skip to main content

Go: error

📅 2026-03-13 ✏️ 2026-03-14 Inside Go CS GO

1 · Go: 错误是值#

go proverbs: Errors are values.

错误是值,不是异常:可以传递、检查、比较(控制流)。

// 实现了 error 接口的类型的值即错误
// src/builtin/builtin.go
type error interface {
	Error() string
}

值须显式处理,这既是优势也是风险。

1.1 · 创建错误

  1. 错误类型(type *Error struct{}):实现error接口的类型
  2. 错误值(var Err* error):通过 errors.New fmt.Errorf 返回的值;及1中定义的错误类型的值
// 以下两个都是go标准库内置的不可导出的错误类型的值
errors.New("")
fmt.Errorf("%w", "") // NOTE: %w 表示wrap错误,可用errors.Unwrap获取这个错误
// 定义自己的错误类型:...

1.2 · 封装错误

go doc errors.Unwrap

实现了Unwrap() error的err都是被封装的错误,可以用errors.Unwrap拿出底层错误

1.3 · 比较错误

errors包提供了Is/As等方法比较判断错误

2 · 最佳实践

  1. 不要忽略错误!
  2. 返回错误的时候,携带(wrap)当前上下文!
  3. 打印错误的时候,将错误作为上下文打印

3 · 其他错误包

4 · 安全处理错误

https://blog.jetbrains.com/go/2026/03/02/secure-go-error-handling-best-practices

因为是值,容易泄露敏感信息(比如凭证、堆栈等信息)?需要控制、净化错误;

4.1 · 安全创建/封装/控制

目标:

  1. 足够的信息用于调试
  2. 为了安全需要净化

原则:

  1. 区分用户、系统可见(内部)的错误
  2. 上下文脱敏:显式控制日志内容
  3. 不透明包装(%w):阻断错误链泄露(为自定义错误类型手动实现Unwrap(),进而手动控制)

4.2 · 安全传播:按信任边界分层处理

  1. 子系统边界:包装为领域错误,隐藏技术细节
  2. API 边界(服务间调用): 转换为标准协议错误(gRPC/JSON)
  3. 公共边界(面向用户):返回通用静态消息 + Request ID

4.3 · 安全记录

  1. 结构化日志:避免字符串拼接,日志处理器可以根据类型进行脱敏处理
  2. 记录前脱敏:仅显式记录调试所需字段,不直接记录整个 struct
  3. 中间件层脱敏:实现Redactor接口自动过滤敏感字段(如密码、Authorization 头)

5 · 其他

https://niketpatel.com/essays/why-go-cant-try

go的错误仅仅可以告知可能失败,而无法知道可能以哪些错误失败;go的错误在编译器可知不充分,无法借助编译器进行语义分析

https://www.jetbrains.com/guide/go/tutorials/handle_errors_in_go