Gin Context传递与取消
Context传递与取消是构建可靠微服务的关键机制,支持请求超时和取消传播。
Context传递机制
从请求Context派生
Go
func (c *Context) Copy() *Context {
cp := Context{
Writer: c.Writer,
Request: c.Request,
Params: c.Params,
engine: c.engine,
}
cp.Writer.(*responseWriter).reset(c.Writer)
return &cp
}
在中间件中传递
Go
func Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 创建带超时的子Context
ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
defer cancel()
// 更新请求Context
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
Context取消传播
客户端断开检测
Go
func handler(c *gin.Context) {
ctx := c.Request.Context()
select {
case <-ctx.Done():
// 客户端断开连接
c.JSON(499, gin.H{"error": "client disconnected"})
return
case result := <-processAsync():
c.JSON(200, result)
}
}
跨服务传播取消
Go
func callExternalAPI(c *gin.Context) {
ctx := c.Request.Context()
req, _ := http.NewRequestWithContext(ctx, "GET", "http://api.example.com", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
if errors.Is(err, context.Canceled) {
// 请求被取消
c.JSON(499, gin.H{"error": "request canceled"})
return
}
c.JSON(500, gin.H{"error": err.Error()})
return
}
defer resp.Body.Close()
}
取消信号传递链
Go
客户端取消
↓
HTTP连接检测
↓
Request.Context().Done()
↓
中间件/处理器接收
↓
下游服务传播
实际应用场景
数据库查询取消
Go
func queryDB(c *gin.Context) {
ctx := c.Request.Context()
var result Data
err := db.WithContext(ctx).First(&result, 1).Error
if err != nil {
if errors.Is(err, context.Canceled) {
c.JSON(499, gin.H{"error": "query canceled"})
return
}
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, result)
}
并发任务取消
text
func concurrentProcess(c *gin.Context) {
ctx := c.Request.Context()
ch := make(chan Result)
go func() {
result := heavyProcess()
select {
case ch <- result:
case <-ctx.Done():
return
}
}()
select {
case <-ctx.Done():
c.JSON(499, gin.H{"error": "canceled"})
case result := <-ch:
c.JSON(200, result)
}
}
注意:务必调用cancel函数释放资源,使用defer cancel()确保执行。
要点总结
- Context传递用于跨层、跨服务传播请求范围数据
- 客户端断开时Request.Context()自动发出取消信号
- 使用WithContext()将取消信号传播到下游调用
- 数据库、HTTP客户端都支持Context取消
- 必须调用cancel函数,推荐使用defer
📝 发现内容有误?点击此处直接编辑