|  |  | package utils
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | import (
 | 
						
						
						
							|  |  | 	"bytes"
 | 
						
						
						
							|  |  | 	"context"
 | 
						
						
						
							|  |  | 	"encoding/json"
 | 
						
						
						
							|  |  | 	"io"
 | 
						
						
						
							|  |  | 	"net/http"
 | 
						
						
						
							|  |  | 	"net/url"
 | 
						
						
						
							|  |  | 	"strings"
 | 
						
						
						
							|  |  | 	"sync"
 | 
						
						
						
							|  |  | 	"time"
 | 
						
						
						
							|  |  | )
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | type HttpClient struct {
 | 
						
						
						
							|  |  | 	client *http.Client
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // NewHttpClient 创建带超时的 HTTP 客户端
 | 
						
						
						
							|  |  | func NewHttpClient(timeout time.Duration) *HttpClient {
 | 
						
						
						
							|  |  | 	return &HttpClient{
 | 
						
						
						
							|  |  | 		client: &http.Client{
 | 
						
						
						
							|  |  | 			Timeout: timeout,
 | 
						
						
						
							|  |  | 		},
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Get 发送 GET 请求
 | 
						
						
						
							|  |  | func (hc *HttpClient) Get(ctx context.Context, rawUrl string, headers map[string]string) ([]byte, int, error) {
 | 
						
						
						
							|  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawUrl, nil)
 | 
						
						
						
							|  |  | 	if err != nil {
 | 
						
						
						
							|  |  | 		return nil, 0, err
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 	for k, v := range headers {
 | 
						
						
						
							|  |  | 		req.Header.Set(k, v)
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	resp, err := hc.client.Do(req)
 | 
						
						
						
							|  |  | 	if err != nil {
 | 
						
						
						
							|  |  | 		return nil, 0, err
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 	defer resp.Body.Close()
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	body, err := io.ReadAll(resp.Body)
 | 
						
						
						
							|  |  | 	return body, resp.StatusCode, err
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // PostJSON 发送 POST 请求,Body 是 JSON
 | 
						
						
						
							|  |  | func (hc *HttpClient) PostJSON(ctx context.Context, rawUrl string, data interface{}, headers map[string]string) ([]byte, int, error) {
 | 
						
						
						
							|  |  | 	bodyBytes, err := json.Marshal(data)
 | 
						
						
						
							|  |  | 	if err != nil {
 | 
						
						
						
							|  |  | 		return nil, 0, err
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, rawUrl, bytes.NewReader(bodyBytes))
 | 
						
						
						
							|  |  | 	if err != nil {
 | 
						
						
						
							|  |  | 		return nil, 0, err
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 	req.Header.Set("Content-Type", "application/json")
 | 
						
						
						
							|  |  | 	for k, v := range headers {
 | 
						
						
						
							|  |  | 		req.Header.Set(k, v)
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	resp, err := hc.client.Do(req)
 | 
						
						
						
							|  |  | 	if err != nil {
 | 
						
						
						
							|  |  | 		return nil, 0, err
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 	defer resp.Body.Close()
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	body, err := io.ReadAll(resp.Body)
 | 
						
						
						
							|  |  | 	return body, resp.StatusCode, err
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // PostForm 发送 POST 表单请求
 | 
						
						
						
							|  |  | func (hc *HttpClient) PostForm(ctx context.Context, rawUrl string, formData map[string]string, headers map[string]string) ([]byte, int, error) {
 | 
						
						
						
							|  |  | 	data := url.Values{}
 | 
						
						
						
							|  |  | 	for k, v := range formData {
 | 
						
						
						
							|  |  | 		data.Set(k, v)
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, rawUrl, strings.NewReader(data.Encode()))
 | 
						
						
						
							|  |  | 	if err != nil {
 | 
						
						
						
							|  |  | 		return nil, 0, err
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 | 
						
						
						
							|  |  | 	for k, v := range headers {
 | 
						
						
						
							|  |  | 		req.Header.Set(k, v)
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	resp, err := hc.client.Do(req)
 | 
						
						
						
							|  |  | 	if err != nil {
 | 
						
						
						
							|  |  | 		return nil, 0, err
 | 
						
						
						
							|  |  | 	}
 | 
						
						
						
							|  |  | 	defer resp.Body.Close()
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 	body, err := io.ReadAll(resp.Body)
 | 
						
						
						
							|  |  | 	return body, resp.StatusCode, err
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | var (
 | 
						
						
						
							|  |  | 	defaultClient *HttpClient
 | 
						
						
						
							|  |  | 	once          sync.Once
 | 
						
						
						
							|  |  | )
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | func GetDefaultClient() *HttpClient {
 | 
						
						
						
							|  |  | 	once.Do(func() {
 | 
						
						
						
							|  |  | 		defaultClient = NewHttpClient(10 * time.Second)
 | 
						
						
						
							|  |  | 	})
 | 
						
						
						
							|  |  | 	return defaultClient
 | 
						
						
						
							|  |  | }
 |