Files
hucan 8ae43bfba9
Some checks failed
Build / build (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
build / Build (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitee (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitlab (push) Has been cancelled
Issue Close Require / issue-close-require (push) Has been cancelled
Issue Check Inactive / issue-check-inactive (push) Has been cancelled
1
2025-06-29 00:36:30 +08:00

146 lines
5.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package httphelper
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// HTTPClient 定义一个通用的 HTTP 客户端结构
type HTTPClient struct {
Client *http.Client // 底层的 http.Client 实例
BaseURL string // 基础 URL所有请求将基于此 URL
Headers map[string]string // 默认请求头
}
// NewHTTPClient 创建一个新的 HTTPClient 实例
// timeout: 请求超时时间,例如 10 * time.Second
// baseURL: 基础 URL例如 "https://api.example.com"
// defaultHeaders: 默认请求头,例如 {"Content-Type": "application/json"}
func NewHTTPClient(timeout time.Duration, baseURL string, defaultHeaders map[string]string) *HTTPClient {
return &HTTPClient{
Client: &http.Client{
Timeout: timeout,
},
BaseURL: baseURL,
Headers: defaultHeaders,
}
}
// applyHeaders 为请求应用默认和自定义请求头
func (c *HTTPClient) applyHeaders(req *http.Request, customHeaders map[string]string) {
// 应用默认请求头
for key, value := range c.Headers {
req.Header.Set(key, value)
}
// 应用自定义请求头(覆盖默认请求头)
for key, value := range customHeaders {
req.Header.Set(key, value)
}
}
// doRequest 执行实际的 HTTP 请求
// method: HTTP 方法 (GET, POST, PUT, DELETE等)
// path: 请求路径,将与 BaseURL 拼接
// requestBody: 请求体数据,如果为 GET/DELETE 请求则为 nil
// customHeaders: 自定义请求头,将覆盖默认请求头
// responseData: 用于存储响应数据的目标结构体(指针类型)
func (c *HTTPClient) doRequest(
method, path string,
requestBody interface{},
customHeaders map[string]string,
responseData interface{},
) error {
// 拼接完整的 URL
url := c.BaseURL + path
var reqBodyReader io.Reader
if requestBody != nil {
// 将请求体编码为 JSON
jsonBody, err := json.Marshal(requestBody)
if err != nil {
return fmt.Errorf("json marshal request body failed: %w", err)
}
reqBodyReader = bytes.NewBuffer(jsonBody)
}
// 创建新的 HTTP 请求
req, err := http.NewRequest(method, url, reqBodyReader)
if err != nil {
return fmt.Errorf("create http request failed: %w", err)
}
// 应用请求头
c.applyHeaders(req, customHeaders)
// 发送请求
resp, err := c.Client.Do(req)
if err != nil {
return fmt.Errorf("send http request failed: %w", err)
}
defer resp.Body.Close()
// 检查 HTTP 状态码
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest {
bodyBytes, _ := io.ReadAll(resp.Body) // 读取错误响应体
return fmt.Errorf("http request failed with status: %d, body: %s", resp.StatusCode, string(bodyBytes))
}
// 如果提供了 responseData则解析响应体
if responseData != nil {
err = json.NewDecoder(resp.Body).Decode(responseData)
if err != nil {
return fmt.Errorf("json decode response body failed: %w", err)
}
}
return nil
}
// Get 发送 GET 请求
// path: 请求路径
// customHeaders: 自定义请求头
// responseData: 用于存储响应数据的目标结构体(指针类型)
func (c *HTTPClient) Get(path string, customHeaders map[string]string, responseData interface{}) error {
return c.doRequest(http.MethodGet, path, nil, customHeaders, responseData)
}
// Post 发送 POST 请求
// path: 请求路径
// requestBody: 请求体数据
// customHeaders: 自定义请求头
// responseData: 用于存储响应数据的目标结构体(指针类型)
func (c *HTTPClient) Post(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error {
return c.doRequest(http.MethodPost, path, requestBody, customHeaders, responseData)
}
// Put 发送 PUT 请求
// path: 请求路径
// requestBody: 请求体数据
// customHeaders: 自定义请求头
// responseData: 用于存储响应数据的目标结构体(指针类型)
func (c *HTTPClient) Put(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error {
return c.doRequest(http.MethodPut, path, requestBody, customHeaders, responseData)
}
// Delete 发送 DELETE 请求
// path: 请求路径
// customHeaders: 自定义请求头
// responseData: 用于存储响应数据的目标结构体(指针类型)
func (c *HTTPClient) Delete(path string, customHeaders map[string]string, responseData interface{}) error {
// DELETE 请求通常没有请求体,但某些 RESTful API 可能支持
return c.doRequest(http.MethodDelete, path, nil, customHeaders, responseData)
}
// Patch 发送 PATCH 请求
// path: 请求路径
// requestBody: 请求体数据
// customHeaders: 自定义请求头
// responseData: 用于存储响应数据的目标结构体(指针类型)
func (c *HTTPClient) Patch(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error {
return c.doRequest(http.MethodPatch, path, requestBody, customHeaders, responseData)
}