Go Web 服务中应为每个 HTTP 请求创建带超时的 context,避免复用全局 context;在 handler 入口或中间件中使用 context.WithTimeout 派生新 context,并透传至 DB、HTTP 等所有阻塞操作。
在 Go Web 服务中,context.Context 是控制请求生命周期、传播取消信号和传递超时的核心机制。合理使用 context 能显著降低因长等待、资源未释放或 goroutine 泄漏带来的性能开销,尤其在高并发、链路调用深的场景下效果明显。
不要复用全局或长期
存活的 context;应在 handler 入口立即派生新 context,并设置合理的截止时间。超时值应略大于下游依赖(如 DB、RPC)的预期耗时,避免过早中断,也防止无限等待。
context.WithTimeout(ctx, 5*time.Second) 替代无限制的 context.Background()
r.Use(func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second); defer cancel(); r = r.WithContext(ctx); h.ServeHTTP(w, r) }) })
ctx.Err() 返回 context.DeadlineExceeded,下游函数应检查并快速退出任何可能挂起的调用——数据库查询、HTTP 客户端请求、channel 接收、锁等待——都应接受 context 并响应取消。标准库(如 net/http.Client、database/sql)已原生支持 context;自定义函数也需显式接收并监听。
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
rows, err := db.QueryContext(ctx, "SELECT ...")
select { case
cancel()(若需)context 取消仅发送信号,不自动释放文件句柄、连接、goroutine 等资源。必须在业务逻辑中显式清理,否则会持续占用内存或连接数。
defer cancel() 配合 WithTimeout 或 WithCancel,确保无论成功失败都释放 cancel 函数defer resp.Body.Close() 或 defer rows.Close(),且这些操作应在 context 取消后仍能安全执行ctx.Done() 触发时退出循环并关闭相关 channelWithValue 仅适合传递请求范围的元数据(如 traceID、用户身份),不应替代函数参数传递核心业务字段。过度使用会增加隐式依赖,降低可读性与可测性,也带来额外分配开销。
WithValue,请定义明确的 key 类型(如 type userIDKey struct{}),避免字符串 key 冲突