jee said

Go语言HTTP客户端开发

unclejee & AI
1310 words
7min read
Go语言HTTP客户端开发

Go语言HTTP客户端开发

Go语言的net/http包提供了强大的HTTP客户端功能。本文将介绍如何使用Go语言进行HTTP客户端开发。

基本HTTP请求

GET请求

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

func main() {
    // 发送GET请求
    resp, err := http.Get("https://api.example.com/data")
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()

    // 读取响应体
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("读取响应失败:", err)
        return
    }

    fmt.Println("状态码:", resp.StatusCode)
    fmt.Println("响应体:", string(body))
}

POST请求

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

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

func main() {
    user := User{Name: "张三", Email: "zhangsan@example.com"}

    // 序列化为JSON
    jsonData, _ := json.Marshal(user)

    // 发送POST请求
    resp, err := http.Post(
        "https://api.example.com/users",
        "application/json",
        bytes.NewBuffer(jsonData),
    )
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("状态码:", resp.StatusCode)
}

PUT和DELETE请求

func main() {
    // PUT请求
    req, _ := http.NewRequest("PUT", "https://api.example.com/users/1", nil)
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()

    // DELETE请求
    req2, _ := http.NewRequest("DELETE", "https://api.example.com/users/1", nil)
    resp2, err := client.Do(req2)
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp2.Body.Close()
}

自定义HTTP客户端

设置超时

import (
    "net/http"
    "time"
)

func main() {
    // 创建自定义客户端
    client := &http.Client{
        Timeout: 10 * time.Second,  // 10秒超时
    }

    resp, err := client.Get("https://api.example.com/data")
    if err != nil {
        fmt.Println("请求超时:", err)
        return
    }
    defer resp.Body.Close()
}

设置请求头

func main() {
    req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)

    // 设置请求头
    req.Header.Set("Authorization", "Bearer token123")
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("User-Agent", "MyApp/1.0")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()
}

重定向控制

func main() {
    client := &http.Client{
        // 不自动跟随重定向
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            return http.ErrUseLastResponse
        },
    }

    resp, err := client.Get("https://api.example.com/redirect")
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()
}

JSON处理

解析JSON响应

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

type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
    CreatedAt string `json:"created_at"`
}

func main() {
    resp, err := http.Get("https://api.example.com/users/1")
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()

    var user User
    err = json.NewDecoder(resp.Body).Decode(&user)
    if err != nil {
        fmt.Println("解析JSON失败:", err)
        return
    }

    fmt.Printf("%+v\n", user)
}

发送JSON请求

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

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

func main() {
    reqBody := CreateUserRequest{
        Name:  "张三",
        Email: "zhangsan@example.com",
    }

    jsonData, _ := json.Marshal(reqBody)

    req, _ := http.NewRequest(
        "POST",
        "https://api.example.com/users",
        bytes.NewBuffer(jsonData),
    )
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()
}

表单处理

发送表单数据

import (
    "fmt"
    "net/http"
    "net/url"
)

func main() {
    // 创建表单数据
    formData := url.Values{}
    formData.Set("username", "zhangsan")
    formData.Set("password", "password123")
    formData.Set("remember", "true")

    // 编码表单数据
    encodedData := formData.Encode()

    // 发送POST请求
    resp, err := http.PostForm(
        "https://api.example.com/login",
        formData,
    )
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()

    fmt.Println("状态码:", resp.StatusCode)
}

文件上传

import (
    "bytes"
    "fmt"
    "mime/multipart"
    "net/http"
    "os"
)

func main() {
    // 打开要上传的文件
    file, err := os.Open("document.pdf")
    if err != nil {
        fmt.Println("打开文件失败:", err)
        return
    }
    defer file.Close()

    // 创建multipart表单
    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)

    // 添加文件字段
    part, err := writer.CreateFormFile("file", "document.pdf")
    if err != nil {
        fmt.Println("创建表单文件失败:", err)
        return
    }
    io.Copy(part, file)

    // 添加其他字段
    writer.WriteField("description", "重要文档")

    writer.Close()

    // 创建请求
    req, _ := http.NewRequest("POST", "https://api.example.com/upload", body)
    req.Header.Set("Content-Type", writer.FormDataContentType())

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("上传失败:", err)
        return
    }
    defer resp.Body.Close()
}

Cookie处理

发送Cookie

func main() {
    req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)

    // 添加Cookie
    req.AddCookie(&http.Cookie{
        Name:  "session_id",
        Value: "abc123",
    })

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()
}

读取Cookie

func main() {
    resp, err := http.Get("https://api.example.com/login")
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()

    // 读取响应中的Cookie
    for _, cookie := range resp.Cookies() {
        fmt.Printf("Cookie: %s = %s\n", cookie.Name, cookie.Value)
    }
}

错误处理

网络错误处理

func makeRequest(url string) error {
    resp, err := http.Get(url)
    if err != nil {
        return fmt.Errorf("请求失败: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode >= 400 {
        return fmt.Errorf("HTTP错误: %d", resp.StatusCode)
    }

    return nil
}

func main() {
    err := makeRequest("https://api.example.com/data")
    if err != nil {
        fmt.Println("请求出错:", err)
        return
    }
    fmt.Println("请求成功")
}

重试机制

import (
    "fmt"
    "net/http"
    "time"
)

func retryRequest(url string, maxRetries int) (*http.Response, error) {
    var resp *http.Response
    var err error

    for i := 0; i < maxRetries; i++ {
        resp, err = http.Get(url)
        if err == nil && resp.StatusCode < 500 {
            return resp, nil
        }

        if i < maxRetries-1 {
            fmt.Printf("重试 %d/%d\n", i+1, maxRetries)
            time.Sleep(time.Second * time.Duration(i+1))
        }
    }

    return resp, err
}

func main() {
    resp, err := retryRequest("https://api.example.com/data", 3)
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()
}

最佳实践

  1. 设置合理的超时:避免请求长时间阻塞
  2. 使用连接池:对于大量请求使用http.Client的连接池
  3. 处理错误状态码:检查HTTP状态码并相应处理
  4. 关闭响应体:使用defer确保响应体被关闭
  5. 使用结构体处理JSON:定义结构体来映射JSON数据

总结

Go语言的HTTP客户端功能强大而简洁,通过net/http包可以轻松完成各种HTTP请求任务。掌握HTTP客户端开发对于现代Web应用开发至关重要。