request.go

This commit is contained in:
李子铭 2024-12-10 15:29:27 +08:00
parent 2ed01d42ea
commit 8ef34584ad
8 changed files with 48 additions and 230 deletions

View File

@ -44,10 +44,10 @@ func req(config *Config, req *po.Param) (url.Values, error) {
} }
func Post(ctx context.Context, uv url.Values) ([]byte, http.Header, error) { func Post(ctx context.Context, uv url.Values) ([]byte, http.Header, error) {
headers := map[string]string{ h := http.Header{
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": []string{"application/x-www-form-urlencoded"},
} }
respBody, respHeader, err := request.Post(ctx, baseUri+"?"+uv.Encode(), nil, request.WithHeaders(headers)) respHeader, respBody, err := request.Post(ctx, baseUri+"?"+uv.Encode(), nil, request.WithHeaders(h))
if err != nil { if err != nil {
return nil, nil, proto.ErrorRequestFail(err.Error()) return nil, nil, proto.ErrorRequestFail(err.Error())
} }

View File

@ -43,10 +43,10 @@ func req(config *Config, req *po.Param) (url.Values, error) {
} }
func Post(ctx context.Context, uv url.Values) ([]byte, http.Header, error) { func Post(ctx context.Context, uv url.Values) ([]byte, http.Header, error) {
headers := map[string]string{ h := http.Header{
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": []string{"application/x-www-form-urlencoded"},
} }
respBody, respHeader, err := request.Post(ctx, baseUri+"?"+uv.Encode(), nil, request.WithHeaders(headers)) respHeader, respBody, err := request.Post(ctx, baseUri+"?"+uv.Encode(), nil, request.WithHeaders(h))
if err != nil { if err != nil {
return nil, nil, proto.ErrorRequestFail(err.Error()) return nil, nil, proto.ErrorRequestFail(err.Error())
} }

View File

@ -10,7 +10,7 @@ import (
"net/http" "net/http"
"plugins/union_pay_cpn/internal/po" "plugins/union_pay_cpn/internal/po"
"plugins/union_pay_cpn/internal/vo" "plugins/union_pay_cpn/internal/vo"
request "plugins/utils/request/v2" "plugins/utils/request"
"plugins/utils/union_pay" "plugins/utils/union_pay"
"strings" "strings"
"time" "time"

View File

@ -10,7 +10,7 @@ import (
"net/http" "net/http"
"plugins/union_pay_redpack/internal/po" "plugins/union_pay_redpack/internal/po"
"plugins/union_pay_redpack/internal/vo" "plugins/union_pay_redpack/internal/vo"
request "plugins/utils/request/v2" "plugins/utils/request"
"plugins/utils/union_pay" "plugins/utils/union_pay"
"time" "time"
) )

View File

@ -11,8 +11,9 @@ import (
// RequestOptions 用于配置请求的各种选项 // RequestOptions 用于配置请求的各种选项
type RequestOptions struct { type RequestOptions struct {
Headers http.Header
Timeout time.Duration Timeout time.Duration
Headers map[string]string
StatusCodeFunc func(int) bool StatusCodeFunc func(int) bool
} }
@ -27,7 +28,7 @@ func WithTimeout(timeout time.Duration) RequestOption {
} }
// WithHeaders 设置请求头的选项函数 // WithHeaders 设置请求头的选项函数
func WithHeaders(headers map[string]string) RequestOption { func WithHeaders(headers http.Header) RequestOption {
return func(options *RequestOptions) { return func(options *RequestOptions) {
options.Headers = headers options.Headers = headers
} }
@ -40,24 +41,27 @@ func WithStatusCodeFunc(statusCodeFunc func(int) bool) RequestOption {
} }
} }
func Post(ctx context.Context, url string, body []byte, options ...RequestOption) ([]byte, http.Header, error) { func Post(ctx context.Context, url string, body []byte, options ...RequestOption) (http.Header, []byte, error) {
return Request(ctx, http.MethodPost, url, body, options...) return Request(ctx, http.MethodPost, url, body, options...)
} }
func Get(ctx context.Context, url string, options ...RequestOption) ([]byte, http.Header, error) { func Get(ctx context.Context, url string, options ...RequestOption) (http.Header, []byte, error) {
return Request(ctx, http.MethodGet, url, nil, options...) return Request(ctx, http.MethodGet, url, nil, options...)
} }
func Put(ctx context.Context, url string, body []byte, options ...RequestOption) ([]byte, http.Header, error) { func Put(ctx context.Context, url string, body []byte, options ...RequestOption) (http.Header, []byte, error) {
return Request(ctx, http.MethodPut, url, body, options...) return Request(ctx, http.MethodPut, url, body, options...)
} }
// Request 封装的HTTP请求函数使用选项模式进行配置 // Request 封装的HTTP请求函数使用选项模式进行配置
func Request(_ context.Context, method, url string, body []byte, options ...RequestOption) ([]byte, http.Header, error) { func Request(_ context.Context, method, url string, body []byte, options ...RequestOption) (http.Header, []byte, error) {
// 设置默认选项 // 设置默认选项
defaultOptions := &RequestOptions{ o := &RequestOptions{
Headers: http.Header{
"Content-Type": []string{"application/json"},
},
Timeout: 15 * time.Second, Timeout: 15 * time.Second,
Headers: make(map[string]string),
StatusCodeFunc: func(code int) bool { StatusCodeFunc: func(code int) bool {
return code == http.StatusOK return code == http.StatusOK
}, },
@ -65,37 +69,32 @@ func Request(_ context.Context, method, url string, body []byte, options ...Requ
// 根据传入的选项更新默认选项 // 根据传入的选项更新默认选项
for _, option := range options { for _, option := range options {
option(defaultOptions) option(o)
} }
req, err := http.NewRequest(method, url, bytes.NewBuffer(body)) req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("创建HTTP请求失败: %v", err) return nil, nil, fmt.Errorf("创建HTTP请求失败: %w", err)
}
// 设置请求头
for key, value := range defaultOptions.Headers {
req.Header.Set(key, value)
} }
req.Header = o.Headers
httpClient := &http.Client{ httpClient := &http.Client{
Timeout: defaultOptions.Timeout, Timeout: o.Timeout,
} }
resp, err := httpClient.Do(req) resp, err := httpClient.Do(req)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("发送HTTP请求失败: %v", err) return nil, nil, fmt.Errorf("发送HTTP请求失败: %w", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
bodyBytes, err := io.ReadAll(resp.Body) bodyBytes, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("读取响应体失败: %v", err) return nil, nil, fmt.Errorf("读取响应体失败: %w", err)
} }
if !defaultOptions.StatusCodeFunc(resp.StatusCode) { if !o.StatusCodeFunc(resp.StatusCode) {
return nil, nil, fmt.Errorf("请求异常:%s", resp.Status) return nil, nil, fmt.Errorf("请求异常:%s", resp.Status)
} }
return bodyBytes, resp.Header, nil return resp.Header, bodyBytes, nil
} }

View File

@ -2,7 +2,6 @@ package request
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"testing" "testing"
@ -12,70 +11,56 @@ import (
func Test_Get(t *testing.T) { func Test_Get(t *testing.T) {
uri := "https://gateway.dev.cdlsxd.cn/adminyx/admin/v1/key_batch/list" uri := "https://gateway.dev.cdlsxd.cn/adminyx/admin/v1/key_batch/list"
headers := map[string]string{
"Content-Type": "application/x-www-form-urlencoded",
}
uv := url.Values{} uv := url.Values{}
uv.Set("page", "1") uv.Set("page", "1")
uv.Set("limit", "2") uv.Set("limit", "2")
respBody, respHeader, err := Get(context.Background(), uri+"?"+uv.Encode(), WithHeaders(headers)) h := http.Header{
"Content-Type": []string{"application/x-www-form-urlencoded"},
}
respHeader, respBody, err := Get(context.Background(), uri+"?"+uv.Encode(), WithHeaders(h))
if err != nil { if err != nil {
fmt.Println(err) t.Error(err)
return return
} }
fmt.Println("响应体:", string(respBody)) t.Logf("响应体:", string(respBody))
fmt.Println("响应头:", respHeader) t.Logf("响应头:", respHeader)
}
func Test_Request(t *testing.T) {
url := "https://gateway.dev.cdlsxd.cn/adminyx/admin/v1/key_batch/get_zip_url/109"
respBody, respHeader, err := Get(context.Background(), url)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("响应体:", string(respBody))
fmt.Println("响应头:", respHeader)
} }
func Test_RequestHeaders(t *testing.T) { func Test_RequestHeaders(t *testing.T) {
url := "http://example.com/api" uri := "http://example.com/api"
body := []byte("request body") body := []byte("request body")
headers := map[string]string{ h := http.Header{
"Content-Type": "application/json", "Content-Type": []string{"application/json"},
"Authorization": "Bearer token", "Authorization": []string{"Bearer token"},
} }
respBody, respHeader, err := Post(context.Background(), url, body, WithTimeout(10*time.Second), WithHeaders(headers)) respHeader, respBody, err := Post(context.Background(), uri, body, WithTimeout(10*time.Second), WithHeaders(h))
if err != nil { if err != nil {
fmt.Println(err) t.Error(err)
return return
} }
fmt.Println("响应体:", string(respBody)) t.Logf("响应体:", string(respBody))
fmt.Println("响应头:", respHeader) t.Logf("响应头:", respHeader)
} }
func Test_RequestStatusCode(t *testing.T) { func Test_RequestStatusCode(t *testing.T) {
url := "http://example.com/api/update" uri := "http://example.com/api/update"
body := []byte("update data") body := []byte("update data")
isSuccess := func(code int) bool { isSuccess := func(code int) bool {
return code == http.StatusOK || code == http.StatusCreated return code == http.StatusOK || code == http.StatusCreated
} }
respBody, respHeader, err := Put(context.Background(), url, body, WithStatusCodeFunc(isSuccess)) respHeader, respBody, err := Put(context.Background(), uri, body, WithStatusCodeFunc(isSuccess))
if err != nil { if err != nil {
fmt.Println(err) t.Error(err)
return return
} }
fmt.Println("响应体:", string(respBody)) t.Logf("响应体:", string(respBody))
fmt.Println("响应头:", respHeader) t.Logf("响应头:", respHeader)
} }

View File

@ -1,100 +0,0 @@
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) {
// 设置默认选项
o := &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(o)
}
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
}

View File

@ -1,66 +0,0 @@
package v2
import (
"context"
"net/http"
"net/url"
"testing"
"time"
)
func Test_Get(t *testing.T) {
uri := "https://gateway.dev.cdlsxd.cn/adminyx/admin/v1/key_batch/list"
uv := url.Values{}
uv.Set("page", "1")
uv.Set("limit", "2")
h := http.Header{
"Content-Type": []string{"application/x-www-form-urlencoded"},
}
respHeader, respBody, err := Get(context.Background(), uri+"?"+uv.Encode(), WithHeaders(h))
if err != nil {
t.Error(err)
return
}
t.Logf("响应体:", string(respBody))
t.Logf("响应头:", respHeader)
}
func Test_RequestHeaders(t *testing.T) {
uri := "http://example.com/api"
body := []byte("request body")
h := http.Header{
"Content-Type": []string{"application/json"},
"Authorization": []string{"Bearer token"},
}
respHeader, respBody, err := Post(context.Background(), uri, body, WithTimeout(10*time.Second), WithHeaders(h))
if err != nil {
t.Error(err)
return
}
t.Logf("响应体:", string(respBody))
t.Logf("响应头:", respHeader)
}
func Test_RequestStatusCode(t *testing.T) {
uri := "http://example.com/api/update"
body := []byte("update data")
isSuccess := func(code int) bool {
return code == http.StatusOK || code == http.StatusCreated
}
respHeader, respBody, err := Put(context.Background(), uri, body, WithStatusCodeFunc(isSuccess))
if err != nil {
t.Error(err)
return
}
t.Logf("响应体:", string(respBody))
t.Logf("响应头:", respHeader)
}