1 new-api点击支付时的逻辑流程
new-api 支付时调用接口/api/user/pay获取支付参数
2 /api/user/pay对应的路由通过api-router.go里获取到的信息是:selfRoute.POST(“/pay”, middleware.CriticalRateLimit(), controller.RequestEpay),所以对应的是topup.go里面的RequestEpay方法
3 请求参数
amount: parseInt(topUpCount),
payment_method: payWay,
4 响应值:
{
"data": {
"device": "pc",
"money": "7.30",
"name": "TUC1",
"notify_url": "https://newapi.xxxx.cn/api/user/epay/notify",
"out_trade_no": "USR1NO1LrJXr1776826739",
"pid": "M190298627950",
"return_url": "https://newapi.xxxx.cn/console/log",
"sign": "b33f108eb641977842b1f112da0ab57d",
"sign_type": "MD5",
"type": "wxpay"
},
"message": "success",
"url": "http://epay.xxxx.cn/fastpay-server/api/pay/S561169349150/submit.php"
}
5 new-apy加签名部分的代码如下:
uri, params, err := client.Purchase(&epay.PurchaseArgs{
Type: req.PaymentMethod,
ServiceTradeNo: tradeNo,
Name: fmt.Sprintf("TUC%d", req.Amount),
Money: strconv.FormatFloat(payMoney, 'f', 2, 64),
Device: epay.PC,
NotifyUrl: notifyUrl,
ReturnUrl: returnUrl,
})
其中epay对应的是:”github.com/Calcium-Ion/go-epay/epay” 对应的项目是:https://github.com/Calcium-Ion/go-epay
5.1 详细代码如下两块
代码块1 order.go
type PurchaseArgs struct {
// 支付类型
Type string
// 商家订单号
ServiceTradeNo string
// 商品名称
Name string
// 金额
Money string
// 设备类型
Device DeviceType
NotifyUrl *url.URL
ReturnUrl *url.URL
}
const (
PurchaseUrl = "/submit.php"
)
// Purchase 生成支付链接和参数
func (c *Client) Purchase(args *PurchaseArgs) (string, map[string]string, error) {
// see https://payment.moe/doc.html
requestParams := map[string]string{
"pid": c.Config.PartnerID,
"type": args.Type,
"out_trade_no": args.ServiceTradeNo,
"notify_url": args.NotifyUrl.String(),
"name": args.Name,
"money": args.Money,
"device": string(args.Device),
"sign_type": "MD5",
"return_url": args.ReturnUrl.String(),
"sign": "",
}
u, err := url.Parse(c.BaseUrl.String())
if err != nil {
return "", nil, err
}
u.Path = path.Join(u.Path, PurchaseUrl)
return u.String(), GenerateParams(requestParams, c.Config.Key), nil
}
代码块2. util.go
package epay
import (
"crypto/md5"
"fmt"
"sort"
"strings"
"github.com/samber/lo"
)
// ParamsFilter 过滤参数,生成签名时需删除 “sign” 和 “sign_type” 参数
func ParamsFilter(params map[string]string) map[string]string {
return lo.PickBy[string, string](params, func(key string, value string) bool {
return !(key == "sign" || key == "sign_type" || value == "")
})
}
// ParamsSort 对参数进行排序,返回排序后的 keys 和 values (go 中 map 为乱序)
func ParamsSort(params map[string]string) ([]string, []string) {
keys := lo.Keys(params)
sort.Strings(keys)
values := lo.Map(keys, func(key string, i int) string {
return params[key]
})
return keys, values
}
// CreateUrlString 生成待签名字符串, ["a", "b", "c"], ["d", "e", "f"] => "a=d&b=e&c=f"
func CreateUrlString(keys []string, values []string) string {
urlString := ""
for i, key := range keys {
urlString += key + "=" + values[i] + "&"
}
// trim 掉最后的 &
return strings.TrimSuffix(urlString, "&")
}
// MD5String 生成 加盐(商户 key) MD5 字符串
func MD5String(urlString string, key string) string {
digest := md5.Sum([]byte(urlString + key))
return fmt.Sprintf("%x", digest)
}
// GenerateParams 生成加签参数
func GenerateParams(params map[string]string, key string) map[string]string {
filtered := ParamsFilter(params)
keys, values := ParamsSort(filtered)
sign := MD5String(CreateUrlString(keys, values), key)
params["sign"] = sign
params["sign_type"] = "MD5"
return params
}
祝贺
剩下是适应接口 xxx/submit.php按照自己的需求去下适配器.