全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-18 8 分钟 ✍️ juanwangdev

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

📝 发现内容有误?点击此处直接编辑

← 上一篇 Gin 配置文件加密与安全
下一篇 → Gin Context值存储与检索
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库