|
|
@@ -6,23 +6,25 @@ import (
|
|
|
"crypto/md5"
|
|
|
"crypto/sha256"
|
|
|
"encoding/hex"
|
|
|
- "encoding/xml"
|
|
|
- "errors"
|
|
|
- "github.com/parnurzeal/gorequest"
|
|
|
- "sort"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
)
|
|
|
|
|
|
//获取请求支付的参数
|
|
|
-func (w *WeChatPayParams) getRequestBody(appId, mchId string, params *WeChatPayParams) (reqs requestBody) {
|
|
|
- reqs = make(requestBody)
|
|
|
+func getRequestBody(appId, mchId string, params *WeChatPayParams) (reqs BodyMap) {
|
|
|
+ reqs = make(BodyMap)
|
|
|
reqs.Set("appid", appId)
|
|
|
reqs.Set("mch_id", mchId)
|
|
|
reqs.Set("nonce_str", params.NonceStr)
|
|
|
- reqs.Set("body", params.Body)
|
|
|
- reqs.Set("out_trade_no", params.OutTradeNo)
|
|
|
- reqs.Set("total_fee", strconv.Itoa(params.TotalFee))
|
|
|
+ if params.Body != "" {
|
|
|
+ reqs.Set("body", params.Body)
|
|
|
+ }
|
|
|
+ if params.OutTradeNo != "" {
|
|
|
+ reqs.Set("out_trade_no", params.OutTradeNo)
|
|
|
+ }
|
|
|
+ if params.TotalFee != -1 {
|
|
|
+ reqs.Set("total_fee", strconv.Itoa(params.TotalFee))
|
|
|
+ }
|
|
|
reqs.Set("spbill_create_ip", params.SpbillCreateIp)
|
|
|
reqs.Set("notify_url", params.NotifyUrl)
|
|
|
reqs.Set("trade_type", params.TradeType)
|
|
|
@@ -66,37 +68,20 @@ func (w *WeChatPayParams) getRequestBody(appId, mchId string, params *WeChatPayP
|
|
|
reqs.Set("receipt", params.Receipt)
|
|
|
}
|
|
|
if params.SceneInfo != "" {
|
|
|
- //marshal, _ := json.Marshal(params.SceneInfo)
|
|
|
- //reqs.Set("scene_info", string(marshal))
|
|
|
reqs.Set("scene_info", params.SceneInfo)
|
|
|
}
|
|
|
- return reqs
|
|
|
-}
|
|
|
-
|
|
|
-//获取SanBox秘钥
|
|
|
-func (w *WeChatPayParams) getSanBoxSignKey(mchId, nonceStr, secretKey, signType string) (key string, err error) {
|
|
|
- body := make(requestBody)
|
|
|
- body.Set("mch_id", mchId)
|
|
|
- body.Set("nonce_str", nonceStr)
|
|
|
-
|
|
|
- //计算沙箱参数Sign
|
|
|
- sanboxSign := getSign(secretKey, signType, body)
|
|
|
- //沙箱环境:获取key后,重新计算Sign
|
|
|
- key, err = getSanBoxSignKey(mchId, nonceStr, sanboxSign)
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
+ if params.TransactionId != "" {
|
|
|
+ reqs.Set("transaction_id", params.TransactionId)
|
|
|
}
|
|
|
- return
|
|
|
+ return reqs
|
|
|
}
|
|
|
|
|
|
-//获取Sign签名和请求支付的参数
|
|
|
-func getSign(secretKey string, signType string, body requestBody) (sign string) {
|
|
|
-
|
|
|
- signStr := getSignString(secretKey, body)
|
|
|
+//本地通过支付参数计算Sign值
|
|
|
+func getLocalSign(secretKey string, signType string, body BodyMap) (sign string) {
|
|
|
+ signStr := sortSignParams(secretKey, body)
|
|
|
//fmt.Println("signStr:", signStr)
|
|
|
var hashSign []byte
|
|
|
- if signType == WX_SignType_MD5 {
|
|
|
-
|
|
|
+ if signType == SignType_MD5 {
|
|
|
hash := md5.New()
|
|
|
hash.Write([]byte(signStr))
|
|
|
hashSign = hash.Sum(nil)
|
|
|
@@ -109,48 +94,43 @@ func getSign(secretKey string, signType string, body requestBody) (sign string)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-//获取根据Key排序后的请求参数字符串
|
|
|
-func getSignString(secretKey string, body requestBody) string {
|
|
|
- keyList := make([]string, 0)
|
|
|
- for k := range body {
|
|
|
- keyList = append(keyList, k)
|
|
|
- }
|
|
|
- sort.Strings(keyList)
|
|
|
- buffer := new(bytes.Buffer)
|
|
|
- for _, k := range keyList {
|
|
|
- buffer.WriteString(k)
|
|
|
- buffer.WriteString("=")
|
|
|
- buffer.WriteString(body[k])
|
|
|
- buffer.WriteString("&")
|
|
|
- }
|
|
|
- buffer.WriteString("key=")
|
|
|
- buffer.WriteString(secretKey)
|
|
|
- return buffer.String()
|
|
|
-}
|
|
|
-
|
|
|
-//获取SanboxKey
|
|
|
-func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
|
|
|
- reqs := make(requestBody)
|
|
|
- reqs.Set("mch_id", mchId)
|
|
|
- reqs.Set("nonce_str", nonceStr)
|
|
|
- reqs.Set("sign", sign)
|
|
|
+//从微信提供的接口获取:SandboxSignKey
|
|
|
+func getSanBoxSign(mchId, nonceStr, secretKey, signType string) (key string, err error) {
|
|
|
+ body := make(BodyMap)
|
|
|
+ body.Set("mch_id", mchId)
|
|
|
+ body.Set("nonce_str", nonceStr)
|
|
|
|
|
|
- reqXml := generateXml(reqs)
|
|
|
- //fmt.Println("req:::", reqXml)
|
|
|
- _, byteList, errorList := gorequest.New().
|
|
|
- Post(wxURL_sanbox_getsignkey).
|
|
|
- Type("xml").
|
|
|
- SendString(reqXml).EndBytes()
|
|
|
- if len(errorList) > 0 {
|
|
|
- return "", errorList[0]
|
|
|
- }
|
|
|
- keyResponse := new(getSignKeyResponse)
|
|
|
- err = xml.Unmarshal(byteList, keyResponse)
|
|
|
+ //计算沙箱参数Sign
|
|
|
+ sanboxSign := getLocalSign(secretKey, signType, body)
|
|
|
+ //沙箱环境:获取key后,重新计算Sign
|
|
|
+ key, err = getSanBoxSignKey(mchId, nonceStr, sanboxSign)
|
|
|
if err != nil {
|
|
|
return "", err
|
|
|
}
|
|
|
- if keyResponse.ReturnCode == "FAIL" {
|
|
|
- return "", errors.New(keyResponse.Retmsg)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+//生成请求XML的Body体
|
|
|
+func generateXml(bm BodyMap) (reqXml string) {
|
|
|
+ buffer := new(bytes.Buffer)
|
|
|
+ buffer.WriteString("<xml>")
|
|
|
+
|
|
|
+ for k, v := range bm {
|
|
|
+ buffer.WriteString("<")
|
|
|
+ buffer.WriteString(k)
|
|
|
+ buffer.WriteString("><![CDATA[")
|
|
|
+ value, ok := v.(int)
|
|
|
+ if ok {
|
|
|
+ value := strconv.Itoa(value)
|
|
|
+ buffer.WriteString(value)
|
|
|
+ } else {
|
|
|
+ buffer.WriteString(v.(string))
|
|
|
+ }
|
|
|
+ buffer.WriteString("]]></")
|
|
|
+ buffer.WriteString(k)
|
|
|
+ buffer.WriteString(">")
|
|
|
}
|
|
|
- return keyResponse.SandboxSignkey, nil
|
|
|
+ buffer.WriteString("</xml>")
|
|
|
+ reqXml = buffer.String()
|
|
|
+ return
|
|
|
}
|