Skip to content

Commit

Permalink
Feature/xhttp update (#356)
Browse files Browse the repository at this point in the history
* update xhttp
  • Loading branch information
iGoogle-ink authored Oct 5, 2023
1 parent 3b8ee6e commit 4b9b76c
Show file tree
Hide file tree
Showing 38 changed files with 1,479 additions and 1,365 deletions.
356 changes: 40 additions & 316 deletions alipay/client.go

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions alipay/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ func TestMain(m *testing.M) {
SetReturnUrl("https://www.fmm.ink").
SetNotifyUrl("https://www.fmm.ink")

// 设置biz_content加密KEY,设置此参数默认开启加密(目前未测试成功)
//client.SetAESKey("KvKUTqSVZX2fUgmxnFyMaQ==")

// 自动同步验签(只支持证书模式)
// 传入 支付宝公钥证书 alipayPublicCert.crt 内容
client.AutoVerifySign(cert.AlipayPublicContentRSA2)
Expand Down
10 changes: 4 additions & 6 deletions alipay/common_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ func FormatURLParam(body gopay.BodyMap) (urlParam string) {
// encryptedData:包括敏感数据在内的完整用户信息的加密数据
// secretKey:AES密钥,支付宝管理平台配置
// beanPtr:需要解析到的结构体指针
// 文档:https://opendocs.alipay.com/mini/introduce/aes
// 文档:https://opendocs.alipay.com/open/common/104567
// 文档:https://opendocs.alipay.com/common/02mse3
func DecryptOpenDataToStruct(encryptedData, secretKey string, beanPtr any) (err error) {
if encryptedData == util.NULL || secretKey == util.NULL {
return errors.New("encryptedData or secretKey is null")
Expand Down Expand Up @@ -76,8 +75,7 @@ func DecryptOpenDataToStruct(encryptedData, secretKey string, beanPtr any) (err
// DecryptOpenDataToBodyMap 解密支付宝开放数据到 BodyMap
// encryptedData:包括敏感数据在内的完整用户信息的加密数据
// secretKey:AES密钥,支付宝管理平台配置
// 文档:https://opendocs.alipay.com/mini/introduce/aes
// 文档:https://opendocs.alipay.com/open/common/104567
// 文档:https://opendocs.alipay.com/common/02mse3
func DecryptOpenDataToBodyMap(encryptedData, secretKey string) (bm gopay.BodyMap, err error) {
if encryptedData == util.NULL || secretKey == util.NULL {
return nil, errors.New("encryptedData or secretKey is null")
Expand Down Expand Up @@ -180,7 +178,7 @@ func systemOauthToken(ctx context.Context, appId string, privateKey *rsa.Private
if !isProd {
baseUrl = sandboxBaseUrlUtf8
}
_, bs, err = xhttp.NewClient().Type(xhttp.TypeForm).Post(baseUrl).SendString(bm.EncodeURLParams()).EndBytes(ctx)
_, bs, err = xhttp.NewClient().Req(xhttp.TypeForm).Post(baseUrl).SendString(bm.EncodeURLParams()).EndBytes(ctx)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -220,7 +218,7 @@ func MonitorHeartbeatSyn(ctx context.Context, appId string, privateKey, signType
}
bm.Set("sign", sign)

_, bs, err = xhttp.NewClient().Type(xhttp.TypeForm).Post(baseUrlUtf8).SendString(bm.EncodeURLParams()).EndBytes(ctx)
_, bs, err = xhttp.NewClient().Req(xhttp.TypeForm).Post(baseUrlUtf8).SendString(bm.EncodeURLParams()).EndBytes(ctx)
if err != nil {
return nil, err
}
Expand Down
5 changes: 2 additions & 3 deletions alipay/customs.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (a *Client) doAliPayCustoms(ctx context.Context, bm gopay.BodyMap, service
bm.Remove("sign_type")
bm.Remove("sign")

sign, err := a.getRsaSign(bm, RSA, a.privateKey)
sign, err := a.getRsaSign(bm, RSA)
if err != nil {
return nil, fmt.Errorf("GetRsaSign Error: %v", err)
}
Expand All @@ -79,8 +79,7 @@ func (a *Client) doAliPayCustoms(ctx context.Context, bm gopay.BodyMap, service
xlog.Debugf("Alipay_Request: %s", bm.JsonBody())
}
// request
httpClient := xhttp.NewClient()
res, bs, err := httpClient.Type(xhttp.TypeForm).Post("https://mapi.alipay.com/gateway.do").SendString(bm.EncodeURLParams()).EndBytes(ctx)
res, bs, err := a.hc.Req(xhttp.TypeForm).Post("https://mapi.alipay.com/gateway.do").SendString(bm.EncodeURLParams()).EndBytes(ctx)
if err != nil {
return nil, err
}
Expand Down
301 changes: 301 additions & 0 deletions alipay/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
package alipay

import (
"context"
"encoding/json"
"fmt"
"time"

"github.com/go-pay/gopay"
"github.com/go-pay/gopay/pkg/util"
"github.com/go-pay/gopay/pkg/xhttp"
"github.com/go-pay/gopay/pkg/xlog"
)

// PostAliPayAPISelfV2 支付宝接口自行实现方法
// 注意:biz_content 需要自行通过bm.SetBodyMap()设置,不设置则没有此参数
// 示例:请参考 client_test.go 的 TestClient_PostAliPayAPISelfV2() 方法
func (a *Client) PostAliPayAPISelfV2(ctx context.Context, bm gopay.BodyMap, method string, aliRsp any) (err error) {
var (
bs, bodyBs []byte
)
// check if there is biz_content
bz := bm.GetInterface("biz_content")
if bzBody, ok := bz.(gopay.BodyMap); ok {
if bodyBs, err = json.Marshal(bzBody); err != nil {
return fmt.Errorf("json.Marshal(%v):%w", bzBody, err)
}
bm.Set("biz_content", string(bodyBs))
}

if bs, err = a.doAliPaySelf(ctx, bm, method); err != nil {
return err
}
if err = json.Unmarshal(bs, aliRsp); err != nil {
return err
}
return nil
}

// 向支付宝发送自定义请求
func (a *Client) doAliPaySelf(ctx context.Context, bm gopay.BodyMap, method string) (bs []byte, err error) {
var (
url, sign string
)
bm.Set("method", method)
// check public parameter
a.checkPublicParam(bm)
// check sign
if bm.GetString("sign") == "" {
sign, err = a.getRsaSign(bm, bm.GetString("sign_type"))
if err != nil {
return nil, fmt.Errorf("GetRsaSign Error: %w", err)
}
bm.Set("sign", sign)
}
if a.DebugSwitch == gopay.DebugOn {
xlog.Debugf("Alipay_Request: %s", bm.JsonBody())
}
if a.IsProd {
url = baseUrlUtf8
} else {
url = sandboxBaseUrlUtf8
}
res, bs, err := a.hc.Req(xhttp.TypeForm).Post(url).SendString(bm.EncodeURLParams()).EndBytes(ctx)
if err != nil {
return nil, err
}
if a.DebugSwitch == gopay.DebugOn {
xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs))
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
}
return bs, nil
}

// 向支付宝发送请求
func (a *Client) doAliPay(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (bs []byte, err error) {
var (
bizContent, url string
bodyBs []byte
)
if bm != nil {
_, has := appAuthTokenInBizContent[method]
if has {
if bodyBs, err = json.Marshal(bm); err != nil {
return nil, fmt.Errorf("json.Marshal:%w", err)
}
bizContent = string(bodyBs)
bm.Remove("app_auth_token")
} else {
aat := bm.GetString("app_auth_token")
bm.Remove("app_auth_token")
if bodyBs, err = json.Marshal(bm); err != nil {
return nil, fmt.Errorf("json.Marshal:%w", err)
}
bizContent = string(bodyBs)
bm.Set("app_auth_token", aat)
}
}
// 处理公共参数
param, err := a.pubParamsHandle(bm, method, bizContent, authToken...)
if err != nil {
return nil, err
}
switch method {
case "alipay.trade.app.pay", "alipay.fund.auth.order.app.freeze":
return []byte(param), nil
case "alipay.trade.wap.pay", "alipay.trade.page.pay", "alipay.user.certify.open.certify":
if !a.IsProd {
return []byte(sandboxBaseUrl + "?" + param), nil
}
return []byte(baseUrl + "?" + param), nil
default:
url = baseUrlUtf8
if !a.IsProd {
url = sandboxBaseUrlUtf8
}
res, bs, err := a.hc.Req(xhttp.TypeForm).Post(url).SendString(param).EndBytes(ctx)
if err != nil {
return nil, err
}
if a.DebugSwitch == gopay.DebugOn {
xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs))
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
}
return bs, nil
}
}

// 向支付宝发送请求
func (a *Client) DoAliPay(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (bs []byte, err error) {
var (
bizContent, url string
bodyBs []byte
)
if bm != nil {
_, has := appAuthTokenInBizContent[method]
if has {
if bodyBs, err = json.Marshal(bm); err != nil {
return nil, fmt.Errorf("json.Marshal:%w", err)
}
bizContent = string(bodyBs)
bm.Remove("app_auth_token")
} else {
aat := bm.GetString("app_auth_token")
bm.Remove("app_auth_token")
if bodyBs, err = json.Marshal(bm); err != nil {
return nil, fmt.Errorf("json.Marshal:%w", err)
}
bizContent = string(bodyBs)
bm.Set("app_auth_token", aat)
}
}
// 处理公共参数
param, err := a.pubParamsHandle(bm, method, bizContent, authToken...)
if err != nil {
return nil, err
}
switch method {
case "alipay.trade.app.pay", "alipay.fund.auth.order.app.freeze":
return []byte(param), nil
case "alipay.trade.wap.pay", "alipay.trade.page.pay", "alipay.user.certify.open.certify":
if !a.IsProd {
return []byte(sandboxBaseUrl + "?" + param), nil
}
return []byte(baseUrl + "?" + param), nil
default:
url = baseUrlUtf8
if !a.IsProd {
url = sandboxBaseUrlUtf8
}
res, bs, err := a.hc.Req(xhttp.TypeForm).Post(url).SendString(param).EndBytes(ctx)
if err != nil {
return nil, err
}
if a.DebugSwitch == gopay.DebugOn {
xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs))
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
}
return bs, nil
}
}

// 保持和官方 SDK 命名方式一致
func (a *Client) PageExecute(ctx context.Context, bm gopay.BodyMap, method string, authToken ...string) (url string, err error) {
var (
bizContent string
bodyBs []byte
)
if bm != nil {
_, has := appAuthTokenInBizContent[method]
if has {
if bodyBs, err = json.Marshal(bm); err != nil {
return "", fmt.Errorf("json.Marshal:%w", err)
}
bizContent = string(bodyBs)
bm.Remove("app_auth_token")
} else {
aat := bm.GetString("app_auth_token")
bm.Remove("app_auth_token")
if bodyBs, err = json.Marshal(bm); err != nil {
return "", fmt.Errorf("json.Marshal:%w", err)
}
bizContent = string(bodyBs)
bm.Set("app_auth_token", aat)
}
}
// 处理公共参数
param, err := a.pubParamsHandle(bm, method, bizContent, authToken...)
if err != nil {
return "", err
}

if !a.IsProd {
return sandboxBaseUrl + "?" + param, nil
}
return baseUrl + "?" + param, nil
}

// 文件上传
func (a *Client) FileRequest(ctx context.Context, bm gopay.BodyMap, file *util.File, method string) (bs []byte, err error) {
var (
bodyStr string
bodyBs []byte
aat string
)
if bm != nil {
aat = bm.GetString("app_auth_token")
bm.Remove("app_auth_token")
if bodyBs, err = json.Marshal(bm); err != nil {
return nil, fmt.Errorf("json.Marshal:%w", err)
}
bodyStr = string(bodyBs)
}
pubBody := make(gopay.BodyMap)
pubBody.Set("app_id", a.AppId).
Set("method", method).
Set("format", "JSON").
Set("charset", a.Charset).
Set("sign_type", a.SignType).
Set("version", "1.0").
Set("scene", "SYNC_ORDER").
Set("timestamp", time.Now().Format(util.TimeLayout))

if a.AppCertSN != util.NULL {
pubBody.Set("app_cert_sn", a.AppCertSN)
}
if a.AliPayRootCertSN != util.NULL {
pubBody.Set("alipay_root_cert_sn", a.AliPayRootCertSN)
}
if a.ReturnUrl != util.NULL {
pubBody.Set("return_url", a.ReturnUrl)
}
if a.location != nil {
pubBody.Set("timestamp", time.Now().In(a.location).Format(util.TimeLayout))
}
if a.NotifyUrl != util.NULL { //如果返回url为空,传过来的返回url不为空
//fmt.Println("url不为空?", a.NotifyUrl)
pubBody.Set("notify_url", a.NotifyUrl)
}
//fmt.Println("notify,", pubBody.JsonBody())
if a.AppAuthToken != util.NULL {
pubBody.Set("app_auth_token", a.AppAuthToken)
}
if aat != util.NULL {
pubBody.Set("app_auth_token", aat)
}
if bodyStr != util.NULL {
pubBody.Set("biz_content", bodyStr)
}
sign, err := a.getRsaSign(pubBody, pubBody.GetString("sign_type"))
if err != nil {
return nil, fmt.Errorf("GetRsaSign Error: %w", err)
}
//pubBody.Set("file_content", file.Content)
pubBody.Set("sign", sign)
if a.DebugSwitch == gopay.DebugOn {
xlog.Debugf("Alipay_Request: %s", pubBody.JsonBody())
}
param := pubBody.EncodeURLParams()
url := baseUrlUtf8 + "&" + param
bm.Reset()
bm.SetFormFile("file_content", file)
res, bs, err := a.hc.Req(xhttp.TypeMultipartFormData).Post(url).
SendMultipartBodyMap(bm).EndBytes(ctx)
if err != nil {
return nil, err
}
if a.DebugSwitch == gopay.DebugOn {
xlog.Debugf("Alipay_Response: %s%d %s%s", xlog.Red, res.StatusCode, xlog.Reset, string(bs))
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
}
return bs, nil
}
Loading

0 comments on commit 4b9b76c

Please sign in to comment.