Context 必须作为第一个参数传入,否则超时、取消、值注入失效;不可存于 struct 字段;WithCancel/WithTimeout 后必须调用 cancel();WithValue 的 key 需为私有类型以避免冲突。

Context 必须作为第一个参数传入
Go 官方约定和几乎所有标准库(net/http、database/sql、http.Client.Do)都要求 context.Context 作为函数的第一个参数。这不是强制语法,但跳过它会导致上下文无法向下传递,超时、取消、值注入全部失效。
常见错误是把 ctx 放在参数末尾,或者封装成结构体字段“偷偷”携带:
// ❌ 错误:ctx 不在首位,调用链中断
func doSomething(data string, ctx context.Context) error { ... }
// ✅ 正确:ctx 必须是第一个参数
func doSomething(ctx context.Context, data string) error { ... }
- 即使函数目前没用到
ctx,只要它可能被上层取消或带 deadline,就该声明为第一个参数 - 不要用
context.Background()或context.TODO()“占位”——那说明你还没想清楚上下文来源 - 如果已有旧函数签名无法改,考虑包装一层新函数,显式透传
ctx
不要在 struct 字段里存 Context
Context 是短期、请求级的,生命周期由调用方控制;而 struct 实例可能长期存活(比如全局 client、缓存对象)。把 ctx 塞进 struct 字段,极易造成 goroutine 泄漏或误用过期上下文。
典型反模式:
type APIClient struct {
ctx context.Context // ❌ 危险:这个 ctx 可能早就 Done() 了
httpClient *http.Client
}
- struct 应只保存可复用、无状态的依赖(如
*http.Client、配置、连接池) - 每个方法调用时,由调用方传入当前有效的
ctx,例如client.Do(ctx, req) - 若需默认行为,可用
context.WithTimeout在方法内部临时派生,但绝不复用 struct 字段里的 ctx
WithCancel / WithTimeout 要配对调用 cancel()
每次调用 context.WithCancel、context.WithTimeout 或 context.WithDeadline,都会返回一个 cancel 函数。不调用它,底层 timer 或 goroutine 可能持续运行,导致内存泄漏或意外唤醒。
常见疏漏场景:
- 在循环中反复调用
WithTimeout却忘了defer cancel() - 提前 return 时跳过了
cancel()调用(尤其有多个 return 分支) - 把
cancel传给子 goroutine 并在其中调用——这会污染父上下文,应由创建者负责取消
安全写法:
ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second) defer cancel() // ✅ 确保执行,无论是否 panic 或提前 return err := doWork(ctx) return err
Value 类型必须是 key-safe,且仅用于传递请求元数据
context.WithValue 的 key 不能是裸字符串或 int——因为不同包可能无意中用相同 key 覆盖彼此的值。必须定义自定义类型作 key,且通常设为 unexported(小写开头)以避免外部篡改。
// ❌ 危险:key 冲突风险高 ctx = context.WithValue(ctx, "user_id", 123) // ✅ 推荐:私有类型 key type ctxKey string const userIDKey ctxKey = "user_id" ctx = context.WithValue(ctx, userIDKey, 123)
-
WithValue只适合传轻量、不可变的请求级元数据(如用户 ID、trace ID、request ID) - 不要传业务对象、数据库连接、logger 实例——这些该通过参数或依赖注入传递
- 下游必须用相同 key 类型取值:
ctx.Value(userIDKey),用字符串取不到
跨服务或中间件传递 trace ID 时,key 类型定义最好统一放在共享包里,否则各模块用各自 key 就断链了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











