Go HTTP客户端:正确发起请求

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

简介

Go (Golang) 是谷歌开发的一种现代编译型语言,非常适合构建高负载网络服务。内置的 net/http 包提供了一个强大且灵活的 HTTP 客户端,可以轻松与 REST API、Web 服务器和其他 HTTP 资源进行交互。然而,尽管看似简单,新手经常犯一些典型错误:忘记关闭响应体、不处理超时或忽略错误。

在本文中,我们将详细讲解如何正确使用 Go 中的 HTTP 客户端。您将学习如何发起 GET 和 POST 请求、管理请求头、配置超时以及处理错误。所有代码示例都可在您的项目中直接使用。

1. 基础:GET 请求与读取响应

执行 GET 请求最简单的方法是使用 http.Get() 函数。但对于生产级代码,建议创建自己的 http.Client 实例——这样可以更好地控制客户端的行为。

简单的 GET 请求

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    // 创建客户端(暂时使用默认设置)
    client := &http.Client{}
    
    // 执行 GET 请求
    resp, err := client.Get("https://api.example.com/data")
    if err != nil {
        fmt.Fprintf(os.Stderr, "请求错误: %v", err)
        os.Exit(1)
    }
    // 重要:关闭响应体
    defer resp.Body.Close()

    // 读取响应体
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Fprintf(os.Stderr, "读取响应体错误: %v", err)
        os.Exit(1)
    }

    fmt.Printf("状态: %s", resp.Status)
    fmt.Printf("响应体: %s", body)
}

关键点:

  • defer resp.Body.Close() — 务必关闭响应体,否则会导致资源泄漏(连接无法返回连接池)。
  • 始终检查 err — 网络不稳定,请求可能失败。
  • 检查 HTTP 响应状态码 (resp.StatusCode),以区分成功 (2xx) 和服务器错误 (4xx, 5xx)。

2. 带请求体和请求头的 POST 请求

要向服务器发送数据(例如 JSON),可以使用 http.Post() 或更灵活的方法 http.NewRequest() 配合 client.Do()。第二种方法更推荐,因为它允许设置请求头和其他参数。

带 JSON 数据的 POST 请求

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

func main() {
    client := &http.Client{}

    // 准备数据
    user := User{Name: "伊万·彼得罗夫", Email: "ivan@example.com"}
    jsonData, err := json.Marshal(user)
    if err != nil {
        fmt.Fprintf(os.Stderr, "JSON 序列化错误: %v", err)
        os.Exit(1)
    }

    // 创建请求
    req, err := http.NewRequest("POST", "https://api.example.com/users", bytes.NewBuffer(jsonData))
    if err != nil {
        fmt.Fprintf(os.Stderr, "创建请求错误: %v", err)
        os.Exit(1)
    }

    // 设置请求头
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer YOUR_TOKEN_HERE")

    // 发送请求
    resp, err := client.Do(req)
    if err != nil {
        fmt.Fprintf(os.Stderr, "请求错误: %v", err)
        os.Exit(1)
    }
    defer resp.Body.Close()

    // 检查状态码
    if resp.StatusCode != http.StatusCreated {
        fmt.Fprintf(os.Stderr, "服务器返回错误: %s", resp.Status)
        os.Exit(1)
    }

    fmt.Println("用户创建成功!")
}

重要

博客

书籍推荐