package v2 import ( "bytes" "context" "fmt" "io" "net/http" "time" ) // RequestOptions 用于配置请求的各种选项 type RequestOptions struct { Headers http.Header Timeout time.Duration StatusCodeFunc func(int) bool } // RequestOption 是一个函数类型,用于设置RequestOptions的各个字段 type RequestOption func(*RequestOptions) // WithTimeout 设置请求超时时间的选项函数 func WithTimeout(timeout time.Duration) RequestOption { return func(options *RequestOptions) { options.Timeout = timeout } } // WithHeaders 设置请求头的选项函数 func WithHeaders(headers http.Header) RequestOption { return func(options *RequestOptions) { options.Headers = headers } } // WithStatusCodeFunc 设置自定义状态码处理函数的选项函数 func WithStatusCodeFunc(statusCodeFunc func(int) bool) RequestOption { return func(options *RequestOptions) { options.StatusCodeFunc = statusCodeFunc } } func Post(ctx context.Context, url string, body []byte, options ...RequestOption) (http.Header, []byte, error) { return Request(ctx, http.MethodPost, url, body, options...) } func Get(ctx context.Context, url string, options ...RequestOption) (http.Header, []byte, error) { return Request(ctx, http.MethodGet, url, nil, options...) } func Put(ctx context.Context, url string, body []byte, options ...RequestOption) (http.Header, []byte, error) { return Request(ctx, http.MethodPut, url, body, options...) } // Request 封装的HTTP请求函数,使用选项模式进行配置 func Request(_ context.Context, method, url string, body []byte, options ...RequestOption) (http.Header, []byte, error) { // 设置默认选项 defaultOptions := &RequestOptions{ Headers: http.Header{ "Content-Type": []string{"application/json"}, }, Timeout: 15 * time.Second, StatusCodeFunc: func(code int) bool { return code == http.StatusOK }, } // 根据传入的选项更新默认选项 for _, option := range options { option(defaultOptions) } req, err := http.NewRequest(method, url, bytes.NewBuffer(body)) if err != nil { return nil, nil, fmt.Errorf("创建HTTP请求失败: %w", err) } httpClient := &http.Client{ Timeout: defaultOptions.Timeout, } resp, err := httpClient.Do(req) if err != nil { return nil, nil, fmt.Errorf("发送HTTP请求失败: %w", err) } defer resp.Body.Close() bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return nil, nil, fmt.Errorf("读取响应体失败: %w", err) } if !defaultOptions.StatusCodeFunc(resp.StatusCode) { return nil, nil, fmt.Errorf("请求异常:%s", resp.Status) } return resp.Header, bodyBytes, nil }