Golang场景下如何正确组织代码消除HTTP请求函数重复逻辑
Golang 重复HTTP请求逻辑重构方案
两个函数的公共逻辑高度重合,核心差异只有请求参数、请求头配置、响应提取规则三点,直接抽离公共请求基函数即可消除所有重复代码,同时可以顺手修复原代码中错误处理缺失、全局变量初始化不合理的隐患。
重构思路
把所有公共逻辑(创建HTTP客户端、构造请求实例、发送请求、关闭响应体、读取响应内容)封装成内部复用函数,可变部分通过参数传入:
- 固定公共逻辑:请求构建、发送、响应读取、资源回收全流程封装
- 可变参数透传:请求方法、URL、自定义请求头通过参数传入
- 差异化响应处理:由上层调用方拿到响应对象/响应体后,自行实现token提取、JSON解析等逻辑
重构后代码
package main import ( "fmt" "io" "net/http" ) const ( cloudAPIBase = "https://cloud-platform-api.com/api" apiVersion = "35.0" basicAuthHash = "<auth-hash>" ) // doRequest 内部通用HTTP请求执行函数,封装所有公共逻辑 func doRequest(method, url string, headers map[string]string) (*http.Response, []byte, error) { client := &http.Client{} req, err := http.NewRequest(method, url, nil) if err != nil { return nil, nil, fmt.Errorf("build request failed: %w", err) } for k, v := range headers { req.Header.Add(k, v) } res, err := client.Do(req) if err != nil { return nil, nil, fmt.Errorf("send request failed: %w", err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { return nil, nil, fmt.Errorf("read response body failed: %w", err) } return res, body, nil } // GetToken 获取云平台访问令牌 func GetToken() (string, error) { headers := map[string]string{ "Accept": fmt.Sprintf("application/*+xml;version=%s", apiVersion), "Authorization": "Basic " + basicAuthHash, } res, _, err := doRequest(http.MethodPost, cloudAPIBase+"/sessions", headers) if err != nil { return "", err } return res.Header.Get("x-vmware-vcloud-access-token"), nil } // HTTPGetter 调用云平台业务API获取JSON响应 func HTTPGetter(method, url, accessToken string) (*http.Response, []byte, error) { headers := map[string]string{ "Accept": fmt.Sprintf("application/json;version=%s", apiVersion), "Authorization": "Bearer " + accessToken, } return doRequest(method, url, headers) }
关键优化说明
- 移除全局
accessToken变量:原实现在包加载阶段就同步调用getToken(),一旦token请求失败会直接导致程序启动崩溃,也无法支持token过期自动刷新的场景,改为调用方按需获取、传入token的方式更灵活可控 - 补全错误传递:原代码仅通过
fmt.Println打印错误,不向上返回错误值,会导致请求失败后后续逻辑拿到空对象运行触发空指针,现在所有错误都包装后返回给上层统一处理 - 常量统一管理:把API版本号、服务地址、基础认证串这类固定配置抽成常量,避免硬编码散落在多个函数中增加维护成本
- 替换废弃API:原代码使用的
ioutil.ReadAll在Go 1.16版本后已迁移至io.ReadAll,重构后直接使用标准库新接口 - 使用标准库常量:用
http.MethodPost这类标准库预定义常量替代手写的HTTP方法字符串,减少笔误概率
内容的提问来源于stack exchange,提问作者Vladimir Fomin
相关产品推荐
相关产品推荐

