touka/docs/httpc.md
wjqserver 4f262b2497 docs: 添加 httpc 集成文档和示例
- 新增 examples/httpc 示例代码
- 新增 docs/httpc.md 文档说明
2026-04-22 07:13:55 +08:00

5 KiB
Raw Blame History

HTTP Client (httpc)

Touka 内置了 httpc HTTP 客户端,方便在请求处理函数中发起出站 HTTP 请求。

核心特性

  • 自动 Context 关联:使用 HTTPC() 方法时,出站请求会自动关联当前请求的 Context
  • 请求取消传播:当客户端断开连接时,出站请求会自动取消,避免资源泄漏
  • 链式调用:保持 httpc 原有的组合式构建器风格

基本用法

简单 GET 请求

r.GET("/proxy", func(c *touka.Context) {
    body, err := c.HTTPC().
        GET("https://api.example.com/data").
        Text()
    if err != nil {
        c.JSON(500, touka.H{"error": err.Error()})
        return
    }
    c.String(200, body)
})

POST JSON 请求

r.POST("/users", func(c *touka.Context) {
    var req struct {
        Name  string `json:"name"`
        Email string `json:"email"`
    }
    c.ShouldBindJSON(&req)

    var result struct {
        ID   int    `json:"id"`
        Name string `json:"name"`
    }

    err := c.HTTPC().
        POST("https://api.example.com/users").
        SetHeader("Authorization", "Bearer "+token).
        SetJSONBody(req).
        DecodeJSON(&result)
    if err != nil {
        c.JSON(500, touka.H{"error": err.Error()})
        return
    }
    c.JSON(200, result)
})

带查询参数

r.GET("/search", func(c *touka.Context) {
    query := c.Query("q")

    var result SearchResult
    err := c.HTTPC().
        GET("https://api.example.com/search").
        SetQueryParam("q", query).
        SetQueryParam("limit", "10").
        DecodeJSON(&result)
    if err != nil {
        c.JSON(500, touka.H{"error": err.Error()})
        return
    }
    c.JSON(200, result)
})

API 对比

旧方式Deprecated

// 需要手动 WithContext容易忘记
resp, err := c.Client().
    WithContext(c.Context()).
    GET(url).
    Execute()

新方式(推荐)

// 自动关联请求 Context
resp, err := c.HTTPC().
    GET(url).
    Execute()

Context 取消机制

使用 HTTPC() 时,当客户端断开连接(如关闭浏览器),出站请求会自动取消:

r.GET("/long-task", func(c *touka.Context) {
    // 这个请求会在客户端断开时自动取消
    resp, err := c.HTTPC().
        GET("https://slow-api.example.com/data").
        Execute()
    
    // 如果客户端已断开err 会包含 context.Canceled
    if errors.Is(err, context.Canceled) {
        return // 客户端已断开,无需处理
    }
    // ...
})

完整 API

contextHTTPClient 方法

方法 返回类型 说明
NewRequestBuilder(method, url) *httpc.RequestBuilder 创建通用请求构建器
GET(url) *httpc.RequestBuilder 创建 GET 请求
POST(url) *httpc.RequestBuilder 创建 POST 请求
PUT(url) *httpc.RequestBuilder 创建 PUT 请求
DELETE(url) *httpc.RequestBuilder 创建 DELETE 请求
PATCH(url) *httpc.RequestBuilder 创建 PATCH 请求
HEAD(url) *httpc.RequestBuilder 创建 HEAD 请求
OPTIONS(url) *httpc.RequestBuilder 创建 OPTIONS 请求

httpc.RequestBuilder 链式方法

返回 *httpc.RequestBuilder(用于链式调用):

方法 说明
WithContext(ctx) 设置 Context通常不需要已自动关联
NoDefaultHeaders() 不添加默认 Header
SetHeader(key, value) 设置 Header
AddHeader(key, value) 添加 Header可重复
SetHeaders(map) 批量设置 Headers
SetQueryParam(key, value) 设置查询参数
AddQueryParam(key, value) 添加查询参数(可重复)
SetQueryParams(map) 批量设置查询参数
SetBody(io.Reader) 设置请求 Body
SetRawBody([]byte) 设置字节 Body

返回 (*httpc.RequestBuilder, error)(可能失败):

方法 说明
SetJSONBody(any) 设置 JSON Body
SetXMLBody(any) 设置 XML Body
SetGOBBody(any) 设置 GOB Body

终结方法

方法 返回类型 说明
Build() (*http.Request, error) 构建请求但不执行
Execute() (*http.Response, error) 执行并返回原始响应
DecodeJSON(v) error 执行并解码 JSON
DecodeXML(v) error 执行并解码 XML
DecodeGOB(v) error 执行并解码 GOB
Text() (string, error) 执行并返回文本
Bytes() ([]byte, error) 执行并返回字节
SSE() (*SSEStream, error) 建立 SSE 流连接

迁移指南

go:fix inline 兼容

旧代码 c.GetHTTPC() 可通过 go fix 自动迁移到 c.Client()

go fix ./...

手动迁移

旧代码 新代码
c.GetHTTPC() c.Client()c.HTTPC()
c.Client().WithContext(ctx).GET(url) c.HTTPC().GET(url)

示例

完整示例请参考 examples/httpc