Golang中HTTP1.1 h2c是否支持多路复用?

Golang中HTTP1.1 h2c是否支持多路复用? 你好

我正在尝试使用Golang发送多个请求,而服务器是http1.1升级到h2c,这意味着只支持TCP,不支持TLS。 有谁知道如何使用单个TCP连接发送多个请求。

当我使用以下命令检查我的服务器时,得到了以下协议信息: curl -vvv --http2 -s ip:port

  • 正在尝试连接 10.10.20.7:8000…
  • 已连接到 amf.free5gc.org (10.10.20.7) 端口 8000 (#0)

GET / HTTP/1.1 Host: amf.free5gc.org:8000 User-Agent: curl/7.79.1 Accept: / Connection: Upgrade, HTTP2-Settings Upgrade: h2c HTTP2-Settings: AAMAAABkAAQCAAAAAAIAAAAA

  • 标记此捆绑包不支持多用途 < HTTP/1.1 101 Switching Protocols < Connection: Upgrade < Upgrade: h2c
  • 收到 101
  • 正在使用 HTTP2,服务器支持多路复用
  • 连接状态已更改 (HTTP/2 已确认)
  • 升级后,将流缓冲区中的 HTTP/2 数据复制到连接缓冲区:len=0
  • 连接状态已更改 (MAX_CONCURRENT_STREAMS == 250)! < HTTP/2 404 < content-type: text/plain < content-length: 18 < date: Wed, 02 Feb 2022 20:53:59 GMT <
  • 正在关闭连接 0 404 page not found/

非常感谢您的帮助。


更多关于Golang中HTTP1.1 h2c是否支持多路复用?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中HTTP1.1 h2c是否支持多路复用?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的,Golang 的 net/http 包支持 HTTP/1.1 升级到 h2c(HTTP/2 over cleartext TCP)的多路复用。你可以使用 golang.org/x/net/http2 包来启用 h2c 客户端。

以下是一个示例代码,展示如何创建一个支持 h2c 的 HTTP 客户端,并使用单个 TCP 连接发送多个并发请求:

package main

import (
    "context"
    "fmt"
    "golang.org/x/net/http2"
    "io"
    "net"
    "net/http"
    "sync"
    "time"
)

func main() {
    // 创建自定义的 Transport 以支持 h2c
    transport := &http2.Transport{
        AllowHTTP: true, // 允许非 TLS 连接
        DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
            // 使用普通 TCP 连接模拟 TLS 拨号
            return net.Dial(network, addr)
        },
    }

    // 创建 HTTP 客户端
    client := &http.Client{
        Transport: transport,
        Timeout:   10 * time.Second,
    }

    // 服务器地址(示例)
    serverURL := "http://amf.free5gc.org:8000"

    var wg sync.WaitGroup
    // 并发发送 5 个请求
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()

            // 创建请求
            req, err := http.NewRequestWithContext(context.Background(), "GET", serverURL, nil)
            if err != nil {
                fmt.Printf("请求 %d 创建失败: %v\n", id, err)
                return
            }

            // 发送请求
            resp, err := client.Do(req)
            if err != nil {
                fmt.Printf("请求 %d 发送失败: %v\n", id, err)
                return
            }
            defer resp.Body.Close()

            // 读取响应体
            body, err := io.ReadAll(resp.Body)
            if err != nil {
                fmt.Printf("请求 %d 读取响应失败: %v\n", id, err)
                return
            }

            fmt.Printf("请求 %d 响应状态: %s, 内容长度: %d\n", id, resp.Status, len(body))
        }(i)
    }

    wg.Wait()
    fmt.Println("所有请求完成")
}

关键点说明:

  1. http2.TransportAllowHTTP: true 允许通过非 TLS 连接使用 HTTP/2。
  2. DialTLS 方法被重写为普通的 net.Dial,以建立 TCP 连接(模拟 TLS 连接行为)。
  3. 客户端会自动处理 HTTP/1.1 到 h2c 的升级,并在同一个连接上多路复用多个请求流。
  4. 示例中使用 goroutine 并发发送请求,这些请求会复用同一个底层 TCP 连接。

注意: 服务器必须支持 h2c 升级(如你的 curl 测试所示)。如果服务器不支持,客户端会自动回退到 HTTP/1.1,但此时连接无法多路复用。

要验证多路复用是否生效,你可以在服务器端监控 TCP 连接数,或检查客户端是否重复使用了连接(例如通过 net/http/httptrace 包跟踪)。

回到顶部