使用Golang编写REST API客户端的实践指南

使用Golang编写REST API客户端的实践指南

package main

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

// Client 结构体用于持有 HTTP 客户端和基础 URL
type Client struct {
    HTTPClient *http.Client
    BaseURL    string
}

// NewClient 创建并返回一个新的 Client 实例
func NewClient(baseURL string) *Client {
    return &Client{
        HTTPClient: &http.Client{Timeout: 10 * time.Second},
        BaseURL:    baseURL,
    }
}

// GetUser 方法通过 ID 获取用户信息
func (c *Client) GetUser(id string) (*User, error) {
    req, err := http.NewRequest("GET", fmt.Sprintf("%s/users/%s", c.BaseURL, id), nil)
    if err != nil {
        return nil, err
    }

    resp, err := c.HTTPClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var user User
    if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
        return nil, err
    }

    return &user, nil
}

// User 结构体表示用户数据模型
type User struct {
    ID   string `json:"id"`
    Name string `json:"name"`
}

func main() {
    client := NewClient("https://api.example.com")
    user, err := client.GetUser("123")
    if err != nil {
        fmt.Printf("获取用户时出错: %v\n", err)
        return
    }
    fmt.Printf("用户: %+v\n", user)
}

更多关于使用Golang编写REST API客户端的实践指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于使用Golang编写REST API客户端的实践指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个很好的REST API客户端基础实现。我来补充几个关键实践点:

1. 添加请求头管理和错误处理

func (c *Client) GetUser(id string) (*User, error) {
    req, err := http.NewRequest("GET", fmt.Sprintf("%s/users/%s", c.BaseURL, id), nil)
    if err != nil {
        return nil, fmt.Errorf("创建请求失败: %w", err)
    }
    
    // 设置请求头
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Accept", "application/json")
    
    resp, err := c.HTTPClient.Do(req)
    if err != nil {
        return nil, fmt.Errorf("请求执行失败: %w", err)
    }
    defer resp.Body.Close()
    
    // 检查HTTP状态码
    if resp.StatusCode != http.StatusOK {
        body, _ := io.ReadAll(resp.Body)
        return nil, fmt.Errorf("API返回错误: %s, 响应: %s", resp.Status, string(body))
    }
    
    var user User
    if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
        return nil, fmt.Errorf("JSON解析失败: %w", err)
    }
    
    return &user, nil
}

2. 实现POST请求示例

// CreateUser 创建新用户
func (c *Client) CreateUser(user *User) (*User, error) {
    jsonData, err := json.Marshal(user)
    if err != nil {
        return nil, fmt.Errorf("JSON编码失败: %w", err)
    }
    
    req, err := http.NewRequest(
        "POST", 
        fmt.Sprintf("%s/users", c.BaseURL), 
        bytes.NewBuffer(jsonData),
    )
    if err != nil {
        return nil, fmt.Errorf("创建请求失败: %w", err)
    }
    
    req.Header.Set("Content-Type", "application/json")
    
    resp, err := c.HTTPClient.Do(req)
    if err != nil {
        return nil, fmt.Errorf("请求执行失败: %w", err)
    }
    defer resp.Body.Close()
    
    if resp.StatusCode != http.StatusCreated {
        body, _ := io.ReadAll(resp.Body)
        return nil, fmt.Errorf("创建用户失败: %s, 响应: %s", resp.Status, string(body))
    }
    
    var createdUser User
    if err := json.NewDecoder(resp.Body).Decode(&createdUser); err != nil {
        return nil, fmt.Errorf("JSON解析失败: %w", err)
    }
    
    return &createdUser, nil
}

3. 添加重试机制

type Client struct {
    HTTPClient *http.Client
    BaseURL    string
    MaxRetries int
}

func (c *Client) doWithRetry(req *http.Request) (*http.Response, error) {
    var resp *http.Response
    var err error
    
    for i := 0; i <= c.MaxRetries; i++ {
        resp, err = c.HTTPClient.Do(req)
        if err == nil && resp.StatusCode < 500 {
            return resp, nil
        }
        
        if i < c.MaxRetries {
            time.Sleep(time.Duration(i) * time.Second) // 指数退避
        }
    }
    
    return resp, err
}

4. 实现请求超时控制

func NewClient(baseURL string) *Client {
    return &Client{
        HTTPClient: &http.Client{
            Timeout: 30 * time.Second,
            Transport: &http.Transport{
                MaxIdleConns:        100,
                MaxIdleConnsPerHost: 10,
                IdleConnTimeout:     90 * time.Second,
            },
        },
        BaseURL:    baseURL,
        MaxRetries: 3,
    }
}

5. 添加请求日志

type loggingTransport struct {
    transport http.RoundTripper
}

func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    start := time.Now()
    resp, err := t.transport.RoundTrip(req)
    duration := time.Since(start)
    
    fmt.Printf("[%s] %s %s - Duration: %v\n", 
        time.Now().Format("2006-01-02 15:04:05"),
        req.Method,
        req.URL.Path,
        duration,
    )
    
    return resp, err
}

// 在Client中使用
func NewClient(baseURL string) *Client {
    return &Client{
        HTTPClient: &http.Client{
            Timeout: 30 * time.Second,
            Transport: &loggingTransport{
                transport: http.DefaultTransport,
            },
        },
        BaseURL: baseURL,
    }
}

这些实践能显著提升REST API客户端的健壮性和可维护性。

回到顶部