package request import ( "bytes" "context" "fmt" "io" "net/http" "time" ) // Options 用于配置请求的各种选项 type Options struct { Headers http.Header StatusCodeFunc func(int) bool Timeout time.Duration } func NewOptions(options ...Option) *Options { o := &Options{ Headers: http.Header{ "Content-Type": []string{"application/json"}, }, StatusCodeFunc: func(code int) bool { return code == http.StatusOK }, Timeout: 15 * time.Second, } for _, option := range options { option(o) } return o } type Option func(*Options) func WithTimeout(timeout time.Duration) Option { return func(options *Options) { options.Timeout = timeout } } func WithHeaders(headers http.Header) Option { return func(options *Options) { options.Headers = headers } } func WithStatusCodeFunc(statusCodeFunc func(int) bool) Option { return func(options *Options) { options.StatusCodeFunc = statusCodeFunc } } func Post(ctx context.Context, url string, body []byte, options ...Option) (http.Header, []byte, error) { return Request(ctx, http.MethodPost, url, body, NewOptions(options...)) } func Get(ctx context.Context, url string, options ...Option) (http.Header, []byte, error) { return Request(ctx, http.MethodGet, url, nil, NewOptions(options...)) } func Put(ctx context.Context, url string, body []byte, options ...Option) (http.Header, []byte, error) { return Request(ctx, http.MethodPut, url, body, NewOptions(options...)) } func Request(_ context.Context, method, url string, body []byte, o *Options) (http.Header, []byte, error) { req, err := http.NewRequest(method, url, bytes.NewBuffer(body)) if err != nil { return nil, nil, fmt.Errorf("创建HTTP请求失败: %w", err) } req.Header = o.Headers httpClient := &http.Client{ Timeout: o.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 !o.StatusCodeFunc(resp.StatusCode) { return nil, nil, fmt.Errorf("请求异常:%s", resp.Status) } return resp.Header, bodyBytes, nil }