贝利信息

Go语言如何使用net http发送请求_HTTP客户端使用说明

日期:2026-01-14 00:00 / 作者:P粉602998670
Go net/http 客户端需显式配置超时、连接复用、重定向等,默认行为易致阻塞或资源耗尽;应复用 client 实例,定制 Transport 控制连接池,用 context 管理超时,手动处理状态码与 Body 关闭。

Go 标准库的 net/http 客户端足够轻量、可靠,绝大多数 HTTP 请求不需要额外引入第三方库。关键在于理解 http.Client 的默认行为和可控点,否则容易踩超时、连接复用、重定向、Cookie 管理等坑。

如何发起一个带超时的 GET 请求

直接用 http.Get 看似简单,但它使用全局默认 http.DefaultClient,没有可配置的超时——一旦后端卡住或网络异常,goroutine 会永久阻塞。必须显式构造带超时的 http.Client

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

req, err := http.NewRequestWithContext(ctx, "GET", "https://www./link/46b315dd44d174daf5617e22b3ac94ca", nil) if err != nil { log.Fatal(err) }

client := &http.Client{} resp, err := client.Do(req) if err != nil { // 注意:err 可能是 net/url.Error(如超时)、net.OpError(如连接拒绝) log.Fatal(err) } defer resp.Body.Close()

如何复用连接并控制并发连接数

HTTP/1.1 默认启用 keep-alive,但若不配置 http.Transport,连接池可能过早关闭、复用率低,或在高并发下耗

尽文件描述符。默认 Transport 对单域名最多复用 2 个空闲连接,远不够生产使用。

transport := &http.Transport{
    MaxIdleConns:        100,
    MaxIdleConnsPerHost: 50,
    IdleConnTimeout:     30 * time.Second,
    KeepAlive:           30 * time.Second,
}

client := &http.Client{Transport: transport}

如何处理重定向、Cookie 和自定义 Header

http.Client 默认自动跟随 301/302 重定向,且默认启用 http.CookieJar(空实现),但若需携带 Cookie 或禁用重定向,必须显式干预。

jar, _ := cookiejar.New(nil)
client := &http.Client{
    Jar: jar,
    CheckRedirect: func(req *http.Request, via []*http.Request) error {
        return http.ErrUseLastResponse // 禁止重定向
    },
}

req, _ := http.NewRequest("POST", "https://www./link/052c3ffc93bd3a4d5fc379bf96fabea8", strings.NewReader({"user":"a"})) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer xyz")

如何安全读取响应 Body 并判断状态码

忘记调用 resp.Body.Close() 会导致连接无法释放;直接读 resp.Body 而不检查 resp.StatusCode,可能把 4xx/5xx 的错误响应当成功数据处理;用 ioutil.ReadAll(已弃用)或 io.ReadAll 读大响应体易 OOM。

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
    body, _ := io.ReadAll(resp.Body)
    log.Printf("HTTP %d: %s", resp.StatusCode, string(body))
    return
}

body, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) }

真正麻烦的不是发请求,而是搞清哪个环节该控制什么:超时归 Clientcontext,连接复用归 Transport,重定向和 Cookie 归 Client 字段,Header 和 Body 处理归 RequestResponse。混用默认值和显式配置,最容易在压测或异常网络下暴露问题。