From 0b264399a3a91a560fc9ae502afbb11695899f80 Mon Sep 17 00:00:00 2001 From: Jerry <85411418@qq.com> Date: Sun, 2 Jun 2024 23:03:07 +0800 Subject: [PATCH] udpate --- alipay/ant.go | 8 +- alipay/ant_test.go | 5 +- alipay/client.go | 2 +- alipay/{request.go => client_request.go} | 13 +- alipay/common_api.go | 2 +- alipay/customs.go | 2 +- alipay/goods_api.go | 11 +- alipay/goods_api_test.go | 9 +- alipay/marketing_api_test.go | 8 +- alipay/marketing_voucher.go | 8 +- allinpay/client.go | 2 +- apple/client.go | 2 +- apple/verify.go | 2 +- go.mod | 3 - go.sum | 6 - lakala/client.go | 2 +- paypal/access_token.go | 2 +- paypal/client.go | 2 +- pkg/xhttp/README.md | 3 + pkg/xhttp/client.go | 103 +++++++++ pkg/xhttp/model.go | 48 ++++ pkg/xhttp/request.go | 268 +++++++++++++++++++++++ pkg/xhttp/transport_default_js.go | 17 ++ pkg/xhttp/transport_default_other.go | 17 ++ qq/client.go | 2 +- qq/oplatform_api.go | 2 +- saobei/client.go | 2 +- wechat/client.go | 2 +- wechat/merchant.go | 2 +- wechat/oplatform_api.go | 2 +- wechat/param.go | 2 +- wechat/payment_api.go | 2 +- wechat/v3/cert.go | 2 +- wechat/v3/client.go | 2 +- wechat/v3/request.go | 2 +- 35 files changed, 504 insertions(+), 63 deletions(-) rename alipay/{request.go => client_request.go} (97%) create mode 100644 pkg/xhttp/README.md create mode 100644 pkg/xhttp/client.go create mode 100644 pkg/xhttp/model.go create mode 100644 pkg/xhttp/request.go create mode 100644 pkg/xhttp/transport_default_js.go create mode 100644 pkg/xhttp/transport_default_other.go diff --git a/alipay/ant.go b/alipay/ant.go index 0ef080aa..df72723d 100644 --- a/alipay/ant.go +++ b/alipay/ant.go @@ -137,15 +137,11 @@ func (a *Client) AntMerchantShopClose(ctx context.Context, bm gopay.BodyMap) (al // ant.merchant.expand.indirect.image.upload(图片上传) // bm参数中 image_content 可不传,file为必传参数 // 文档地址:https://opendocs.alipay.com/open/04fgwt -func (a *Client) AntMerchantExpandIndirectImageUpload(ctx context.Context, bm gopay.BodyMap, file *gopay.File) (aliRsp *AntMerchantExpandIndirectImageUploadRsp, err error) { - if file == nil { - return nil, fmt.Errorf("file is nil") - } - err = bm.CheckEmptyError("image_type") +func (a *Client) AntMerchantExpandIndirectImageUpload(ctx context.Context, bm gopay.BodyMap) (aliRsp *AntMerchantExpandIndirectImageUploadRsp, err error) { + err = bm.CheckEmptyError("image_type", "image_content") if err != nil { return nil, err } - bm.Set("image_content", file) var bs []byte if bs, err = a.FileUploadRequest(ctx, bm, "ant.merchant.expand.indirect.image.upload"); err != nil { return nil, err diff --git a/alipay/ant_test.go b/alipay/ant_test.go index d826076c..19009e51 100644 --- a/alipay/ant_test.go +++ b/alipay/ant_test.go @@ -129,12 +129,13 @@ func TestAntMerchantExpandIndirectImageUpload(t *testing.T) { return } f := &gopay.File{ - Name: "logo", + Name: "logo.png", Content: allBs, } bm := make(gopay.BodyMap) bm.Set("image_type", "png") - aliRsp, err := client.AntMerchantExpandIndirectImageUpload(ctx, bm, f) + bm.SetFormFile("image_content", f) + aliRsp, err := client.AntMerchantExpandIndirectImageUpload(ctx, bm) if err != nil { xlog.Errorf("client.AntMerchantExpandIndirectImageUpload(),error:%+v", err) return diff --git a/alipay/client.go b/alipay/client.go index a6abccb5..ef8d26e7 100644 --- a/alipay/client.go +++ b/alipay/client.go @@ -11,7 +11,7 @@ import ( "github.com/go-pay/crypto/xpem" "github.com/go-pay/crypto/xrsa" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xlog" "github.com/go-pay/xtime" ) diff --git a/alipay/request.go b/alipay/client_request.go similarity index 97% rename from alipay/request.go rename to alipay/client_request.go index 0d2a0347..b19d6fa4 100644 --- a/alipay/request.go +++ b/alipay/client_request.go @@ -7,7 +7,7 @@ import ( "time" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xlog" "github.com/go-pay/xtime" ) @@ -321,9 +321,11 @@ func (a *Client) FileUploadRequest(ctx context.Context, bm gopay.BodyMap, method if aat != gopay.NULL { pubBody.Set("app_auth_token", aat) } - // 文件也需要签名 + // 文件上传除文件外其他参数也需要签名 for k, v := range bm { - pubBody.Set(k, v) + if _, ok := v.(*gopay.File); !ok { + pubBody.Set(k, v) + } } // sign sign, err := a.getRsaSign(pubBody, pubBody.GetString("sign_type")) @@ -336,10 +338,9 @@ func (a *Client) FileUploadRequest(ctx context.Context, bm gopay.BodyMap, method } pubBody.Set("sign", sign) if a.DebugSwitch == gopay.DebugOn { - xlog.Debugf("Alipay_Request: %s", pubBody.JsonBody()) + xlog.Debugf("Alipay_Query_Request: %s", pubBody.JsonBody()) } - param := pubBody.EncodeURLParams() - url := baseUrlUtf8 + "&" + param + url := baseUrlUtf8 + "&" + pubBody.EncodeURLParams() res, bs, err := a.hc.Req(xhttp.TypeMultipartFormData).Post(url). SendMultipartBodyMap(bm).EndBytes(ctx) diff --git a/alipay/common_api.go b/alipay/common_api.go index 59ddbf26..c7d87061 100644 --- a/alipay/common_api.go +++ b/alipay/common_api.go @@ -17,7 +17,7 @@ import ( "github.com/go-pay/crypto/xpem" "github.com/go-pay/crypto/xrsa" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xtime" ) diff --git a/alipay/customs.go b/alipay/customs.go index 5acdc71d..45bd583c 100644 --- a/alipay/customs.go +++ b/alipay/customs.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xlog" ) diff --git a/alipay/goods_api.go b/alipay/goods_api.go index c8706033..07a62524 100644 --- a/alipay/goods_api.go +++ b/alipay/goods_api.go @@ -10,14 +10,11 @@ import ( // alipay.merchant.item.file.upload(商品文件上传接口) // 文档地址:https://opendocs.alipay.com/apis/api_4/alipay.merchant.item.file.upload -func (a *Client) MerchantItemFileUpload(ctx context.Context, file *gopay.File) (aliRsp *MerchantItemFileUploadRsp, err error) { - if file == nil { - return nil, fmt.Errorf("file is nil") +func (a *Client) MerchantItemFileUpload(ctx context.Context, bm gopay.BodyMap) (aliRsp *MerchantItemFileUploadRsp, err error) { + err = bm.CheckEmptyError("scene", "file_content") + if err != nil { + return nil, err } - bm := make(gopay.BodyMap) - bm.Set("scene", "SYNC_ORDER") //素材固定值 - bm.Set("file_content", file) //素材固定值 - var bs []byte if bs, err = a.FileUploadRequest(ctx, bm, "alipay.merchant.item.file.upload"); err != nil { return nil, err diff --git a/alipay/goods_api_test.go b/alipay/goods_api_test.go index 5dff884a..b8f91ba2 100644 --- a/alipay/goods_api_test.go +++ b/alipay/goods_api_test.go @@ -23,12 +23,15 @@ func TestMerchantItemFileUpload(t *testing.T) { return } f := &gopay.File{ - Name: "logo", + Name: "logo.png", Content: allBs, } - aliRsp, err := client.MerchantItemFileUpload(ctx, f) + bm := make(gopay.BodyMap) + bm.Set("scene", "SYNC_ORDER") // 素材固定值 + bm.SetFormFile("file_content", f) + aliRsp, err := client.MerchantItemFileUpload(ctx, bm) if err != nil { - xlog.Errorf("client.AntMerchantExpandIndirectImageUpload(),error:%+v", err) + xlog.Errorf("client.MerchantItemFileUpload(),error:%+v", err) return } xlog.Debug("aliRsp:", *aliRsp) diff --git a/alipay/marketing_api_test.go b/alipay/marketing_api_test.go index 8a89a965..363f937d 100644 --- a/alipay/marketing_api_test.go +++ b/alipay/marketing_api_test.go @@ -121,15 +121,15 @@ func TestMarketingMaterialImageUpload(t *testing.T) { return } f := &gopay.File{ - Name: "logo", + Name: "logo.png", Content: allBs, } bm := make(gopay.BodyMap) bm.Set("file_key", "PROMO_VOUCHER_IMAGE"). - Set("merchant_access_mode", "SELF_MODE") - aliRsp, err := client.MarketingMaterialImageUpload(ctx, bm, f) + SetFormFile("file_content", f) + aliRsp, err := client.MarketingMaterialImageUpload(ctx, bm) if err != nil { - xlog.Errorf("client.AntMerchantExpandIndirectImageUpload(),error:%+v", err) + xlog.Errorf("client.MarketingMaterialImageUpload(),error:%+v", err) return } xlog.Debug("aliRsp:", *aliRsp) diff --git a/alipay/marketing_voucher.go b/alipay/marketing_voucher.go index 67ad45b2..837c9098 100644 --- a/alipay/marketing_voucher.go +++ b/alipay/marketing_voucher.go @@ -11,14 +11,10 @@ import ( // alipay.marketing.material.image.upload(营销图片资源上传接口) // bm参数中 file_content 可不传,file为必传参数 // 文档地址:https://opendocs.alipay.com/open/389b24b6_alipay.marketing.material.image.upload -func (a *Client) MarketingMaterialImageUpload(ctx context.Context, bm gopay.BodyMap, file *gopay.File) (aliRsp *MarketingMaterialImageUploadRsp, err error) { - if file == nil { - return nil, fmt.Errorf("file is nil") - } - if err = bm.CheckEmptyError("file_key"); err != nil { +func (a *Client) MarketingMaterialImageUpload(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingMaterialImageUploadRsp, err error) { + if err = bm.CheckEmptyError("file_key", "file_content"); err != nil { return nil, err } - bm.Set("file_content", file) var bs []byte if bs, err = a.FileUploadRequest(ctx, bm, "alipay.marketing.material.image.upload"); err != nil { return nil, err diff --git a/allinpay/client.go b/allinpay/client.go index f86fdccf..34672f6e 100644 --- a/allinpay/client.go +++ b/allinpay/client.go @@ -15,8 +15,8 @@ import ( "github.com/go-pay/crypto/xpem" "github.com/go-pay/crypto/xrsa" "github.com/go-pay/gopay" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/util" - "github.com/go-pay/xhttp" ) type Client struct { diff --git a/apple/client.go b/apple/client.go index 965f9b11..3b8852dc 100644 --- a/apple/client.go +++ b/apple/client.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" ) // Client AppleClient diff --git a/apple/verify.go b/apple/verify.go index 49a9a6be..c7e45311 100644 --- a/apple/verify.go +++ b/apple/verify.go @@ -3,7 +3,7 @@ package apple import ( "context" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" ) const ( diff --git a/go.mod b/go.mod index 6594fff0..d802661d 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,7 @@ require ( github.com/go-pay/crypto v0.0.1 github.com/go-pay/errgroup v0.0.2 github.com/go-pay/util v0.0.2 - github.com/go-pay/xhttp v0.0.2 github.com/go-pay/xlog v0.0.2 github.com/go-pay/xtime v0.0.2 golang.org/x/crypto v0.23.0 ) - -require github.com/go-pay/bm v0.0.2 // indirect diff --git a/go.sum b/go.sum index e5c59a8b..1c4e4846 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,12 @@ -github.com/go-pay/bm v0.0.2 h1:CLa5hNTIm6uv8HSWGWd4moZbuOzQqJo5HcScXBBSY/E= -github.com/go-pay/bm v0.0.2/go.mod h1:nyglxC5YS4+gVaO9TxLMI0I/naFUqwffdt5n6llM8uM= github.com/go-pay/crypto v0.0.1 h1:B6InT8CLfSLc6nGRVx9VMJRBBazFMjr293+jl0lLXUY= github.com/go-pay/crypto v0.0.1/go.mod h1:41oEIvHMKbNcYlWUlRWtsnC6+ASgh7u29z0gJXe5bes= github.com/go-pay/errgroup v0.0.2 h1:5mZMdm0TDClDm2S3G0/sm0f8AuQRtz0dOrTHDR9R8Cc= github.com/go-pay/errgroup v0.0.2/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8= github.com/go-pay/util v0.0.2 h1:goJ4f6kNY5zzdtg1Cj8oWC+Cw7bfg/qq2rJangMAb9U= github.com/go-pay/util v0.0.2/go.mod h1:qM8VbyF1n7YAPZBSJONSPMPsPedhUTktewUAdf1AjPg= -github.com/go-pay/xhttp v0.0.2 h1:O8rnd/d03WsboFtUthwFMg61ikHRfYHyD1m0JiUx60g= -github.com/go-pay/xhttp v0.0.2/go.mod h1:BnuvXpLKkXTFMOBc5MTb0hxdrstwunbzQPJUZOsNbt4= github.com/go-pay/xlog v0.0.2 h1:kUg5X8/5VZAPDg1J5eGjA3MG0/H5kK6Ew0dW/Bycsws= github.com/go-pay/xlog v0.0.2/go.mod h1:DbjMADPK4+Sjxj28ekK9goqn4zmyY4hql/zRiab+S9E= github.com/go-pay/xtime v0.0.2 h1:7YR4/iuELsEHpJ6LUO0SVK80hQxDO9MLCfuVYIiTCRM= github.com/go-pay/xtime v0.0.2/go.mod h1:W1yRbJaSt4CSBcdAtLBQ8xajiN/Pl5hquGczUcUE9xE= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= diff --git a/lakala/client.go b/lakala/client.go index dbe85f3f..08616205 100644 --- a/lakala/client.go +++ b/lakala/client.go @@ -12,8 +12,8 @@ import ( "time" "github.com/go-pay/gopay" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/util" - "github.com/go-pay/xhttp" "github.com/go-pay/xlog" ) diff --git a/paypal/access_token.go b/paypal/access_token.go index ad966609..e84d8079 100644 --- a/paypal/access_token.go +++ b/paypal/access_token.go @@ -9,8 +9,8 @@ import ( "time" "github.com/go-pay/gopay" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/util/retry" - "github.com/go-pay/xhttp" "github.com/go-pay/xlog" ) diff --git a/paypal/client.go b/paypal/client.go index a61a18f0..bd359d41 100644 --- a/paypal/client.go +++ b/paypal/client.go @@ -4,7 +4,7 @@ import ( "context" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" ) // Client PayPal支付客户端 diff --git a/pkg/xhttp/README.md b/pkg/xhttp/README.md new file mode 100644 index 00000000..02a68b9f --- /dev/null +++ b/pkg/xhttp/README.md @@ -0,0 +1,3 @@ +## xhttp + +http request library for Go \ No newline at end of file diff --git a/pkg/xhttp/client.go b/pkg/xhttp/client.go new file mode 100644 index 00000000..fb5bdb92 --- /dev/null +++ b/pkg/xhttp/client.go @@ -0,0 +1,103 @@ +package xhttp + +import ( + "crypto/tls" + "net" + "net/http" + "time" +) + +type Client struct { + HttpClient *http.Client + bodySize int // body size limit(MB), default is 10MB +} + +func defaultClient() *Client { + return &Client{ + HttpClient: &http.Client{ + Timeout: 60 * time.Second, + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: defaultTransportDialContext(&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }), + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + DisableKeepAlives: true, + ForceAttemptHTTP2: true, + }, + }, + bodySize: 10, // default is 10MB + } +} + +// NewClient , default tls.Config{InsecureSkipVerify: true} +func NewClient() (client *Client) { + return defaultClient() +} + +func (c *Client) SetTransport(transport *http.Transport) (client *Client) { + c.HttpClient.Transport = transport + return c +} + +func (c *Client) SetTLSConfig(tlsCfg *tls.Config) (client *Client) { + c.HttpClient.Transport.(*http.Transport).TLSClientConfig = tlsCfg + return c +} + +func (c *Client) SetTimeout(timeout time.Duration) (client *Client) { + c.HttpClient.Timeout = timeout + return c +} + +// set body size (MB), default is 10MB +func (c *Client) SetBodySize(sizeMB int) (client *Client) { + c.bodySize = sizeMB + return c +} + +// typeStr is request type and response type +// default is TypeJSON +// first param is request type +// second param is response data type +func (c *Client) Req(typeStr ...string) *Request { + var ( + reqTp = TypeJSON // default + resTp = ResTypeJSON // default + tLen = len(typeStr) + ) + switch { + case tLen == 1: + tpp := typeStr[0] + if _, ok := _ReqContentTypeMap[tpp]; ok { + reqTp = tpp + } + case tLen > 1: + // first param is request type + tpp := typeStr[0] + if _, ok := _ReqContentTypeMap[tpp]; ok { + reqTp = tpp + } + // second param is response data type + stpp := typeStr[1] + if _, ok := _ResTypeMap[stpp]; ok { + resTp = stpp + } + } + if c == nil { + c = defaultClient() + } + r := &Request{ + client: c, + Header: make(http.Header), + requestType: reqTp, + responseType: resTp, + } + r.Header.Set("Content-Type", _ReqContentTypeMap[reqTp]) + return r +} diff --git a/pkg/xhttp/model.go b/pkg/xhttp/model.go new file mode 100644 index 00000000..79a519a4 --- /dev/null +++ b/pkg/xhttp/model.go @@ -0,0 +1,48 @@ +package xhttp + +import "encoding/json" + +const ( + GET = "GET" + POST = "POST" + PUT = "PUT" + DELETE = "DELETE" + PATCH = "PATCH" + + ResTypeJSON = "json" + ResTypeXML = "xml" + + TypeJSON = "json" + TypeXML = "xml" + TypeFormData = "form-data" + TypeMultipartFormData = "multipart-form-data" +) + +var ( + _ReqContentTypeMap = map[string]string{ + TypeJSON: "application/json", + TypeXML: "application/xml", + TypeFormData: "application/x-www-form-urlencoded", + TypeMultipartFormData: "multipart/form-data", + } + + _ResTypeMap = map[string]string{ + ResTypeJSON: "application/json", + ResTypeXML: "application/xml", + } +) + +func ConvertToString(v any) (str string) { + if v == nil { + return "" + } + var ( + bs []byte + err error + ) + if bs, err = json.Marshal(v); err != nil { + return "" + } + str = string(bs) + return +} diff --git a/pkg/xhttp/request.go b/pkg/xhttp/request.go new file mode 100644 index 00000000..b3af2023 --- /dev/null +++ b/pkg/xhttp/request.go @@ -0,0 +1,268 @@ +package xhttp + +import ( + "bytes" + "context" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "sort" + "strings" + + "github.com/go-pay/gopay" +) + +type Request struct { + client *Client + Header http.Header + formString string + jsonByte []byte + url string + method string + requestType string + responseType string + multipartBodyMap map[string]any + err error +} + +func (r *Request) Get(url string) *Request { + r.method = GET + r.url = url + return r +} + +func (r *Request) Post(url string) *Request { + r.method = POST + r.url = url + return r +} + +func (r *Request) Put(url string) *Request { + r.method = PUT + r.url = url + return r +} + +func (r *Request) Delete(url string) *Request { + r.method = DELETE + r.url = url + return r +} + +func (r *Request) Patch(url string) *Request { + r.method = PATCH + r.url = url + return r +} + +// ===================================================================================================================== + +func (r *Request) SendStruct(v any) (c *Request) { + if v == nil { + return r + } + bs, err := json.Marshal(v) + if err != nil { + r.err = fmt.Errorf("json.Marshal(%+v):%w", v, err) + return r + } + switch r.requestType { + case TypeJSON: + r.jsonByte = bs + case TypeXML, TypeFormData: + body := make(map[string]any) + if err = json.Unmarshal(bs, &body); err != nil { + r.err = fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), body, err) + return r + } + r.formString = FormatURLParam(body) + } + return r +} + +func (r *Request) SendBodyMap(bm map[string]any) (client *Request) { + if bm == nil { + return r + } + switch r.requestType { + case TypeJSON: + bs, err := json.Marshal(bm) + if err != nil { + r.err = fmt.Errorf("json.Marshal(%+v):%w", bm, err) + return r + } + r.jsonByte = bs + case TypeXML, TypeFormData: + r.formString = FormatURLParam(bm) + } + return r +} + +func (r *Request) SendMultipartBodyMap(bm map[string]any) (client *Request) { + if bm == nil { + return r + } + switch r.requestType { + case TypeJSON: + bs, err := json.Marshal(bm) + if err != nil { + r.err = fmt.Errorf("json.Marshal(%+v):%w", bm, err) + return r + } + r.jsonByte = bs + case TypeXML, TypeFormData: + r.formString = FormatURLParam(bm) + case TypeMultipartFormData: + r.multipartBodyMap = bm + } + return r +} + +// encodeStr: url.Values.Encode() or jsonBody +func (r *Request) SendString(encodeStr string) (client *Request) { + switch r.requestType { + case TypeJSON: + r.jsonByte = []byte(encodeStr) + case TypeXML, TypeFormData: + r.formString = encodeStr + } + return r +} + +// ===================================================================================================================== + +func (r *Request) EndBytes(ctx context.Context) (res *http.Response, bs []byte, err error) { + if r.err != nil { + return nil, nil, r.err + } + var ( + body io.Reader + bw *multipart.Writer + ) + // multipart-form-data + if r.requestType == TypeMultipartFormData { + body = &bytes.Buffer{} + bw = multipart.NewWriter(body.(io.Writer)) + } + + switch r.method { + case GET: + // do nothing + case POST, PUT, DELETE, PATCH: + switch r.requestType { + case TypeJSON: + if r.jsonByte != nil { + body = strings.NewReader(string(r.jsonByte)) + } + case TypeFormData: + if r.formString != "" { + body = strings.NewReader(r.formString) + } + case TypeMultipartFormData: + for k, v := range r.multipartBodyMap { + // file 参数 + if file, ok := v.(*gopay.File); ok { + fw, e := bw.CreateFormFile(k, file.Name) + if e != nil { + return nil, nil, e + } + _, _ = fw.Write(file.Content) + continue + } + // text 参数 + switch vs := v.(type) { + case string: + _ = bw.WriteField(k, vs) + default: + _ = bw.WriteField(k, ConvertToString(v)) + } + } + _ = bw.Close() + r.Header.Set("Content-Type", bw.FormDataContentType()) + case TypeXML: + if r.formString != "" { + body = strings.NewReader(r.formString) + } + default: + return nil, nil, errors.New("Request type Error ") + } + default: + return nil, nil, errors.New("Only support GET and POST and PUT and DELETE ") + } + + // request + req, err := http.NewRequestWithContext(ctx, r.method, r.url, body) + if err != nil { + return nil, nil, err + } + req.Header = r.Header + res, err = r.client.HttpClient.Do(req) + if err != nil { + return nil, nil, err + } + defer res.Body.Close() + bs, err = io.ReadAll(io.LimitReader(res.Body, int64(r.client.bodySize<<20))) // default 10MB change the size you want + if err != nil { + return nil, nil, err + } + return res, bs, nil +} + +func (r *Request) EndStruct(ctx context.Context, v any) (res *http.Response, err error) { + res, bs, err := r.EndBytes(ctx) + if err != nil { + return nil, err + } + if res.StatusCode != http.StatusOK { + return res, fmt.Errorf("StatusCode(%d) != 200", res.StatusCode) + } + + switch r.responseType { + case ResTypeJSON: + err = json.Unmarshal(bs, &v) + if err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), v, err) + } + return res, nil + case ResTypeXML: + err = xml.Unmarshal(bs, &v) + if err != nil { + return nil, fmt.Errorf("xml.Unmarshal(%s, %+v):%w", string(bs), v, err) + } + return res, nil + default: + return nil, errors.New("responseType Type Wrong") + } +} + +func FormatURLParam(body map[string]any) (urlParam string) { + var ( + buf strings.Builder + keys []string + ) + for k := range body { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v, ok := body[k].(string) + if !ok { + v = ConvertToString(body[k]) + } + if v != "" { + buf.WriteString(url.QueryEscape(k)) + buf.WriteByte('=') + buf.WriteString(url.QueryEscape(v)) + buf.WriteByte('&') + } + } + if buf.Len() <= 0 { + return "" + } + return buf.String()[:buf.Len()-1] +} diff --git a/pkg/xhttp/transport_default_js.go b/pkg/xhttp/transport_default_js.go new file mode 100644 index 00000000..9bdee1a4 --- /dev/null +++ b/pkg/xhttp/transport_default_js.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build js && wasm +// +build js,wasm + +package xhttp + +import ( + "context" + "net" +) + +func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) { + return nil +} diff --git a/pkg/xhttp/transport_default_other.go b/pkg/xhttp/transport_default_other.go new file mode 100644 index 00000000..a67fd465 --- /dev/null +++ b/pkg/xhttp/transport_default_other.go @@ -0,0 +1,17 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !(js && wasm) +// +build !js !wasm + +package xhttp + +import ( + "context" + "net" +) + +func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) { + return dialer.DialContext +} diff --git a/qq/client.go b/qq/client.go index c5204b12..15fe081f 100644 --- a/qq/client.go +++ b/qq/client.go @@ -14,7 +14,7 @@ import ( "sync" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xlog" ) diff --git a/qq/oplatform_api.go b/qq/oplatform_api.go index 02511d0c..311d227c 100644 --- a/qq/oplatform_api.go +++ b/qq/oplatform_api.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" ) // 获取开放平台,access_token 返回结构体 diff --git a/saobei/client.go b/saobei/client.go index 386ac8af..dc4c7178 100644 --- a/saobei/client.go +++ b/saobei/client.go @@ -8,7 +8,7 @@ import ( "sync" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xlog" ) diff --git a/wechat/client.go b/wechat/client.go index 14fff0ae..4cbce50c 100644 --- a/wechat/client.go +++ b/wechat/client.go @@ -14,7 +14,7 @@ import ( "sync" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xlog" ) diff --git a/wechat/merchant.go b/wechat/merchant.go index 4ce0cede..ca5bc64b 100644 --- a/wechat/merchant.go +++ b/wechat/merchant.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/xlog" ) diff --git a/wechat/oplatform_api.go b/wechat/oplatform_api.go index f38b5870..2f3f21fa 100644 --- a/wechat/oplatform_api.go +++ b/wechat/oplatform_api.go @@ -10,7 +10,7 @@ package wechat import ( "context" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" ) // GetOauth2AccessToken 微信第三方登录,code 换取 access_token diff --git a/wechat/param.go b/wechat/param.go index 772847cd..f369548e 100644 --- a/wechat/param.go +++ b/wechat/param.go @@ -16,8 +16,8 @@ import ( "strings" "github.com/go-pay/gopay" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/util" - "github.com/go-pay/xhttp" "github.com/go-pay/xlog" "golang.org/x/crypto/pkcs12" ) diff --git a/wechat/payment_api.go b/wechat/payment_api.go index 59577c08..4ded7bc3 100644 --- a/wechat/payment_api.go +++ b/wechat/payment_api.go @@ -21,7 +21,7 @@ import ( xaes "github.com/go-pay/crypto/aes" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" ) // ParseNotifyToBodyMap 解析微信支付异步通知的结果到BodyMap(推荐) diff --git a/wechat/v3/cert.go b/wechat/v3/cert.go index 754ff3e3..7d48d8ef 100644 --- a/wechat/v3/cert.go +++ b/wechat/v3/cert.go @@ -19,10 +19,10 @@ import ( "github.com/go-pay/crypto/xpem" "github.com/go-pay/errgroup" "github.com/go-pay/gopay" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/util" "github.com/go-pay/util/convert" "github.com/go-pay/util/retry" - "github.com/go-pay/xhttp" "github.com/go-pay/xlog" "github.com/go-pay/xtime" ) diff --git a/wechat/v3/client.go b/wechat/v3/client.go index 06aafd78..358d2ec8 100644 --- a/wechat/v3/client.go +++ b/wechat/v3/client.go @@ -7,7 +7,7 @@ import ( "github.com/go-pay/crypto/xpem" "github.com/go-pay/gopay" - "github.com/go-pay/xhttp" + "github.com/go-pay/gopay/pkg/xhttp" ) // ClientV3 微信支付 V3 diff --git a/wechat/v3/request.go b/wechat/v3/request.go index e44b1ff2..7d0455b3 100644 --- a/wechat/v3/request.go +++ b/wechat/v3/request.go @@ -7,8 +7,8 @@ import ( "time" "github.com/go-pay/gopay" + "github.com/go-pay/gopay/pkg/xhttp" "github.com/go-pay/util" - "github.com/go-pay/xhttp" "github.com/go-pay/xlog" )