This commit is contained in:
jiangyong27 2024-11-05 20:42:13 +08:00
parent 10492bab9f
commit 65fedea2db
3 changed files with 267 additions and 0 deletions

17
weixin/utils.go Normal file
View File

@ -0,0 +1,17 @@
package weixin
import (
"math/rand"
"time"
)
func randomStr(length int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < length; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}

142
weixin/wxpay_params.go Normal file
View File

@ -0,0 +1,142 @@
package weixin
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/hex"
"encoding/xml"
"fmt"
"io"
"sort"
"strconv"
"strings"
)
type Params map[string]string
func (p Params) Set(k string, v interface{}) {
p[k] = fmt.Sprintf("%v", v)
}
func (p Params) GetString(k string) string {
s, _ := p[k]
return s
}
func (p Params) GetUint64(k string) uint64 {
s, _ := strconv.ParseUint(p[k], 10, 64)
return s
}
func (p Params) GetInt64(k string) int64 {
i, _ := strconv.ParseInt(p.GetString(k), 10, 64)
return i
}
func (p Params) GetInt(k string) int64 {
i, _ := strconv.ParseInt(p.GetString(k), 10, 64)
return i
}
func (p Params) GetFloat64(k string) float64 {
f, _ := strconv.ParseFloat(p.GetString(k), 64)
return f
}
func (p Params) GetBool(k string) bool {
b, _ := strconv.ParseBool(p.GetString(k))
return b
}
// XML解码
func (p Params) Decode(body []byte) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
var (
d *xml.Decoder
start *xml.StartElement
)
buf := bytes.NewBuffer(body)
d = xml.NewDecoder(buf)
for {
tok, err := d.Token()
if err != nil {
break
}
switch t := tok.(type) {
case xml.StartElement:
start = &t
case xml.CharData:
if t = bytes.TrimSpace(t); len(t) > 0 {
p.Set(start.Name.Local, string(t))
}
}
}
return nil
}
// XML编码
func (p Params) Encode() []byte {
var buf bytes.Buffer
buf.WriteString(`<xml>`)
for k, v := range p {
buf.WriteString(`<`)
buf.WriteString(k)
buf.WriteString(`><![CDATA[`)
buf.WriteString(v)
buf.WriteString(`]]></`)
buf.WriteString(k)
buf.WriteString(`>`)
}
buf.WriteString(`</xml>`)
return buf.Bytes()
}
// 验证签名
func (p Params) CheckSign(key string) bool {
return p.GetString("sign") == p.SignMd5(key)
}
// 生成签名
func (p Params) getSignStr(key string) string {
var keys = make([]string, 0, len(p))
for k, _ := range p {
if k != "sign" {
keys = append(keys, k)
}
}
sort.Strings(keys)
var buf bytes.Buffer
for _, k := range keys {
if len(p.GetString(k)) > 0 {
buf.WriteString(k)
buf.WriteString(`=`)
buf.WriteString(p.GetString(k))
buf.WriteString(`&`)
}
}
buf.WriteString(`key=`)
buf.WriteString(key)
return buf.String()
}
// 生成签名
func (p Params) SignMd5(key string) string {
sum := md5.Sum([]byte(p.getSignStr(key)))
str := hex.EncodeToString(sum[:])
return strings.ToUpper(str)
}
// 生成签名
func (p Params) SignHmacSha256(key string) string {
h := hmac.New(sha256.New, []byte(key))
io.WriteString(h, p.getSignStr(key))
str := hex.EncodeToString(h.Sum(nil))
return strings.ToUpper(str)
}

108
weixin/wxpay_partner.go Normal file
View File

@ -0,0 +1,108 @@
package weixin
import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
)
var (
ErrUserPaying = errors.New("USERPAYING")
)
type WxpayPartnerConfig struct {
MchId string
AppId string
ApiKeyV2 string
}
type WxpayPartner struct {
config *WxpayPartnerConfig
stdClient *http.Client
}
type MicroPayRequest struct {
SubMchId string
SubAppId string
GoodsName string
OutTradeNo string
TotalFee int64
AuthCode string
ServerIp string
Attach string
}
func NewWxpayPartner(cfg *WxpayPartnerConfig) *WxpayPartner {
return &WxpayPartner{
config: cfg,
stdClient: &http.Client{},
}
}
func (p *WxpayPartner) MicroPay(req *MicroPayRequest) error {
params := make(Params)
params.Set("appid", p.config.AppId)
params.Set("mch_id", p.config.MchId)
params.Set("sub_mch_id", req.SubMchId)
params.Set("nonce_str", randomStr(32))
params.Set("body", req.GoodsName)
params.Set("out_trade_no", req.OutTradeNo)
params.Set("total_fee", req.TotalFee)
params.Set("auth_code", req.AuthCode)
if req.ServerIp == "" {
params.Set("spbill_create_ip", "113.248.223.215")
} else {
params.Set("spbill_create_ip", req.ServerIp)
}
if req.Attach != "" {
params.Set("attach", req.Attach)
}
if req.SubAppId != "" {
params.Set("sub_appid", req.SubAppId)
}
params.Set("sign", params.SignMd5(p.config.ApiKeyV2))
reqUrl := "https://api.mch.weixin.qq.com/pay/micropay"
body, err := p.post(reqUrl, params)
if err != nil {
return err
}
result := make(Params)
result.Decode(body)
if result.GetString("return_code") != "SUCCESS" {
return errors.New(string(body))
}
if result.GetString("result_code") != "SUCCESS" {
if result.GetString("err_code") == "USERPAYING" {
return ErrUserPaying
}
return fmt.Errorf("%s:%s",
result.GetString("err_code"), result.GetString("err_code_des"))
}
return nil
}
// 发送请求
func (c *WxpayPartner) post(url string, params Params) ([]byte, error) {
var httpc *http.Client
httpc = c.stdClient
buf := bytes.NewBuffer(params.Encode())
resp, err := httpc.Post(url, "application/xml; charset=utf-8", buf)
if err != nil {
return nil, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}