Go包开发:确保总页数仅被获取一次的实现需求
针对你开发Go HTTP客户端的需求,我整理了一个简洁且符合Go编程风格的实现方案,完美解决首次获取总页数并缓存的问题:
核心实现思路
- 用结构体封装HTTP客户端、缓存的总页数、并发控制锁和已获取标记
- 首次调用
GetPage时,从响应中提取总页数并缓存到Client实例 Total方法直接返回缓存的总页数,同时保证并发安全
完整代码示例
package main import ( "encoding/json" "fmt" "net/http" "sync" ) // 替换为你的API实际返回的响应结构 type PageResponse struct { Data []interface{} `json:"data"` TotalPages int `json:"total_pages"` CurrentPage int `json:"current_page"` } type Client struct { httpClient *http.Client totalPages int mu sync.RWMutex // 读写锁,优化并发场景下的性能 fetched bool // 标记是否已获取过总页数 } // NewClient 创建一个初始化好的Client实例 func NewClient() *Client { return &Client{ httpClient: &http.Client{}, } } // GetPage 获取指定页码的数据,首次调用时自动缓存总页数 func (c *Client) GetPage(page int) (*PageResponse, error) { // 替换为你的实际API地址 url := fmt.Sprintf("https://your-service-url.com/api/pages?page=%d", page) resp, err := c.httpClient.Get(url) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() var pageResp PageResponse if err := json.NewDecoder(resp.Body).Decode(&pageResp); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } // 仅在首次获取时更新总页数 c.mu.Lock() defer c.mu.Unlock() if !c.fetched { c.totalPages = pageResp.TotalPages c.fetched = true } return &pageResp, nil } // Total 返回缓存的总页数,如果尚未获取过则返回0 func (c *Client) Total() int { c.mu.RLock() defer c.mu.RUnlock() return c.totalPages } // 可选:如果需要在未调用GetPage时返回明确错误,可修改Total方法如下 // func (c *Client) Total() (int, error) { // c.mu.RLock() // defer c.mu.RUnlock() // if !c.fetched { // return 0, fmt.Errorf("total pages not available yet - call GetPage first") // } // return c.totalPages, nil // }
关键细节说明
- 并发安全:使用
sync.RWMutex而非普通sync.Mutex,因为Total是读操作,多个goroutine可以同时读取缓存值,只有当GetPage更新缓存时才会独占锁,性能更优。 - 缓存逻辑:
fetched标记确保只有第一次请求会更新总页数——如果你的服务总页数可能动态变化(比如数据实时更新),可以移除这个标记,每次请求都同步更新缓存的总页数。 - HTTP连接复用:内置的
http.Client会维护一个连接池,避免每次请求都新建TCP连接,大幅降低请求耗时,符合HTTP最佳实践。 - 错误处理:用
%w包装错误,保留原始错误链,方便上层调用方进行错误判断和处理。
内容的提问来源于stack exchange,提问作者Mikołaj Hołysz
相关产品推荐
相关产品推荐

