Jerry 6 yıl önce
ebeveyn
işleme
8723cb2be7
3 değiştirilmiş dosya ile 166 ekleme ve 64 silme
  1. 58 0
      util.go
  2. 62 45
      wechat_client_test.go
  3. 46 19
      wechat_servier_api.go

+ 58 - 0
util.go

@@ -2,7 +2,10 @@ package gopay
 
 
 import (
 import (
 	"crypto/tls"
 	"crypto/tls"
+	"encoding/xml"
+	"fmt"
 	"github.com/parnurzeal/gorequest"
 	"github.com/parnurzeal/gorequest"
+	"io"
 	"math/rand"
 	"math/rand"
 	"reflect"
 	"reflect"
 	"strconv"
 	"strconv"
@@ -63,6 +66,61 @@ func (bm BodyMap) Remove(key string) {
 	delete(bm, key)
 	delete(bm, key)
 }
 }
 
 
+type xmlMapEntry struct {
+	XMLName xml.Name
+	Value   string `xml:",chardata"`
+}
+
+func (bm BodyMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
+	if len(bm) == 0 {
+		return nil
+	}
+
+	err := e.EncodeToken(start)
+	if err != nil {
+		return err
+	}
+	var value string
+	for k, v := range bm {
+		//验证参数类型
+		fmt.Println("k:", k)
+		vKind := reflect.ValueOf(v).Kind()
+		//fmt.Println("vKind:", vKind)
+		switch vKind {
+		case reflect.String:
+			value = v.(string)
+		case reflect.Int:
+			value = Int2String(v.(int))
+		case reflect.Int64:
+			value = Int642String(v.(int64))
+		case reflect.Float32:
+			value = Float32ToString(v.(float32))
+		case reflect.Float64:
+			value = Float64ToString(v.(float64))
+		default:
+			value = ""
+		}
+		e.Encode(xmlMapEntry{XMLName: xml.Name{Local: k}, Value: value})
+	}
+
+	return e.EncodeToken(start.End())
+}
+
+func (bm *BodyMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+	for {
+		var e xmlMapEntry
+		err := d.Decode(&e)
+		if err == io.EOF {
+			break
+		} else if err != nil {
+			return err
+		}
+		bm.Set(e.XMLName.Local, e.Value)
+		//(*bm)[e.XMLName.Local] = e.Value
+	}
+	return nil
+}
+
 //HttpAgent
 //HttpAgent
 func HttpAgent() (agent *gorequest.SuperAgent) {
 func HttpAgent() (agent *gorequest.SuperAgent) {
 	agent = gorequest.New()
 	agent = gorequest.New()

+ 62 - 45
wechat_client_test.go

@@ -3,56 +3,58 @@ package gopay
 import (
 import (
 	"crypto/md5"
 	"crypto/md5"
 	"encoding/hex"
 	"encoding/hex"
+	"encoding/xml"
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 )
 )
 
 
-//func TestWeChatClient_UnifiedOrder(t *testing.T) {
-//	//初始化微信客户端
-//	//    appId:应用ID
-//	//    MchID:商户ID
-//	//    apiKey:API秘钥值
-//	//    isProd:是否是正式环境
-//	client := NewWeChatClient(AppID, MchID_iguiyu, ApiKey_iguiyu, true)
-//
-//	number := GetRandomString(32)
-//	fmt.Println("out_trade_no:", number)
-//	//初始化参数Map
-//	body := make(BodyMap)
-//	body.Set("nonce_str", GetRandomString(32))
-//	body.Set("body", "测试支付")
-//	body.Set("out_trade_no", number)
-//	body.Set("total_fee", 1)
-//	body.Set("spbill_create_ip", "127.0.0.1")
-//	body.Set("notify_url", "http://www.gopay.ink")
-//	body.Set("trade_type", TradeType_H5)
-//	body.Set("device_info", "WEB")
-//	body.Set("sign_type", SignType_MD5)
-//
-//	sceneInfo := make(map[string]map[string]string)
-//	h5Info := make(map[string]string)
-//	h5Info["type"] = "Wap"
-//	h5Info["wap_url"] = "http://www.gopay.ink"
-//	h5Info["wap_name"] = "H5测试支付"
-//	sceneInfo["h5_info"] = h5Info
-//	body.Set("scene_info", sceneInfo)
-//
-//	body.Set("openid", OpenID)
-//
-//	//请求支付下单,成功后得到结果
-//	wxRsp, err := client.UnifiedOrder(body)
-//	if err != nil {
-//		fmt.Println("Error:", err)
-//		return
-//	}
-//	fmt.Println("wxRsp:", *wxRsp)
-//	//timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
-//	////获取小程序需要的paySign
-//	//pac := "prepay_id=" + wxRsp.PrepayId
-//	//paySign := GetMiniPaySign(AppID, wxRsp.NonceStr, pac, SignType_MD5, timeStamp, ApiKey_iguiyu)
-//	//fmt.Println("paySign:", paySign)
-//}
+func TestWeChatClient_UnifiedOrder(t *testing.T) {
+	//初始化微信客户端
+	//    appId:应用ID
+	//    MchID:商户ID
+	//    apiKey:API秘钥值
+	//    isProd:是否是正式环境
+	client := NewWeChatClient(AppID, MchID_iguiyu, ApiKey_iguiyu, false)
+
+	number := GetRandomString(32)
+	fmt.Println("out_trade_no:", number)
+	//初始化参数Map
+	body := make(BodyMap)
+	body.Set("nonce_str", GetRandomString(32))
+	body.Set("body", "测试支付")
+	body.Set("out_trade_no", number)
+	body.Set("total_fee", 1)
+	body.Set("spbill_create_ip", "127.0.0.1")
+	body.Set("notify_url", "https://api.iguiyu.com/gy_pay/wechat/testnotify")
+	body.Set("trade_type", TradeType_Native)
+	body.Set("device_info", "WEB")
+	body.Set("sign_type", SignType_MD5)
+
+	//sceneInfo := make(map[string]map[string]string)
+	//h5Info := make(map[string]string)
+	//h5Info["type"] = "Wap"
+	//h5Info["wap_url"] = "http://www.gopay.ink"
+	//h5Info["wap_name"] = "H5测试支付"
+	//sceneInfo["h5_info"] = h5Info
+	//body.Set("scene_info", sceneInfo)
+	//
+	//body.Set("openid", OpenID)
+
+	//请求支付下单,成功后得到结果
+	wxRsp, err := client.UnifiedOrder(body)
+	if err != nil {
+		fmt.Println("Error:", err)
+		return
+	}
+	fmt.Println("wxRsp:", *wxRsp)
+	//timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
+	////获取小程序需要的paySign
+	//pac := "prepay_id=" + wxRsp.PrepayId
+	//paySign := GetMiniPaySign(AppID, wxRsp.NonceStr, pac, SignType_MD5, timeStamp, ApiKey_iguiyu)
+	//fmt.Println("paySign:", paySign)
+}
+
 //
 //
 //func TestWeChatClient_QueryOrder(t *testing.T) {
 //func TestWeChatClient_QueryOrder(t *testing.T) {
 //	//初始化微信客户端
 //	//初始化微信客户端
@@ -397,3 +399,18 @@ func TestMd5(t *testing.T) {
 	upper := strings.ToUpper(hex.EncodeToString(sum))
 	upper := strings.ToUpper(hex.EncodeToString(sum))
 	fmt.Println(" ssad  ", upper)
 	fmt.Println(" ssad  ", upper)
 }
 }
+
+func TestBodyMap_MarshalXML(t *testing.T) {
+
+	maps := make(BodyMap)
+	maps.Set("name", "jerry")
+	maps.Set("age", 28)
+	maps.Set("phone", "13212345678")
+
+	bytes, err := xml.Marshal(&maps)
+	if err != nil {
+		fmt.Println("err:", err)
+	}
+	fmt.Println("ssss:", string(bytes))
+
+}

+ 46 - 19
wechat_servier_api.go

@@ -13,11 +13,38 @@ import (
 	"encoding/xml"
 	"encoding/xml"
 	"errors"
 	"errors"
 	"github.com/parnurzeal/gorequest"
 	"github.com/parnurzeal/gorequest"
+	"io/ioutil"
 	"net/http"
 	"net/http"
 	"reflect"
 	"reflect"
 	"strings"
 	"strings"
 )
 )
 
 
+//解析微信支付完成后的Notify参数到BodyMap,并验证Sign值
+//    req:*http.Request
+//    apiKey:API秘钥值
+//    signType:签名类型 MD5 或 HMAC-SHA256(默认请填写 MD5)
+//    返回参数bm:Notify请求的参数
+//    返回参数ok:是否验证通过
+//    返回参数sign:根据参数计算的sign值,非微信返回参数中的Sign
+//    返回参数err:错误信息
+func ParseWeChatNotifyParamAndVerifySign(req *http.Request, apiKey string, signType string) (bm BodyMap, ok bool, sign string, err error) {
+	bs, err := ioutil.ReadAll(req.Body)
+	defer req.Body.Close()
+	if err != nil {
+		return nil, false, null, err
+	}
+	//获取Notify请求参数
+	bm = make(BodyMap)
+	err = xml.Unmarshal(bs, &bm)
+	if err != nil {
+		return nil, false, null, err
+	}
+	//验证Sign值
+	sign = getLocalSign(apiKey, signType, bm)
+	ok = sign == bm.Get("sign")
+	return
+}
+
 //解析支付完成后的Notify信息
 //解析支付完成后的Notify信息
 func ParseNotifyResult(req *http.Request) (notifyRsp *WeChatNotifyRequest, err error) {
 func ParseNotifyResult(req *http.Request) (notifyRsp *WeChatNotifyRequest, err error) {
 	notifyRsp = new(WeChatNotifyRequest)
 	notifyRsp = new(WeChatNotifyRequest)
@@ -29,25 +56,6 @@ func ParseNotifyResult(req *http.Request) (notifyRsp *WeChatNotifyRequest, err e
 	return
 	return
 }
 }
 
 
-type WeChatNotifyResponse struct {
-	ReturnCode string `xml:"return_code"`
-	ReturnMsg  string `xml:"return_msg"`
-}
-
-//返回数据给微信
-func (this *WeChatNotifyResponse) ToXmlString() (xmlStr string) {
-	buffer := new(bytes.Buffer)
-	buffer.WriteString("<xml><return_code><![CDATA[")
-	buffer.WriteString(this.ReturnCode)
-	buffer.WriteString("]]></return_code>")
-
-	buffer.WriteString("<return_msg><![CDATA[")
-	buffer.WriteString(this.ReturnMsg)
-	buffer.WriteString("]]></return_msg></xml>")
-	xmlStr = buffer.String()
-	return
-}
-
 //支付通知的签名验证和参数签名后的Sign
 //支付通知的签名验证和参数签名后的Sign
 //    apiKey:API秘钥值
 //    apiKey:API秘钥值
 //    signType:签名类型 MD5 或 HMAC-SHA256(默认请填写 MD5)
 //    signType:签名类型 MD5 或 HMAC-SHA256(默认请填写 MD5)
@@ -99,6 +107,25 @@ func VerifyPayResultSign(apiKey string, signType string, notifyRsp *WeChatNotify
 	return
 	return
 }
 }
 
 
+type WeChatNotifyResponse struct {
+	ReturnCode string `xml:"return_code"`
+	ReturnMsg  string `xml:"return_msg"`
+}
+
+//返回数据给微信
+func (this *WeChatNotifyResponse) ToXmlString() (xmlStr string) {
+	buffer := new(bytes.Buffer)
+	buffer.WriteString("<xml><return_code><![CDATA[")
+	buffer.WriteString(this.ReturnCode)
+	buffer.WriteString("]]></return_code>")
+
+	buffer.WriteString("<return_msg><![CDATA[")
+	buffer.WriteString(this.ReturnMsg)
+	buffer.WriteString("]]></return_msg></xml>")
+	xmlStr = buffer.String()
+	return
+}
+
 //JSAPI支付,统一下单获取支付参数后,再次计算出小程序用的paySign
 //JSAPI支付,统一下单获取支付参数后,再次计算出小程序用的paySign
 //    appId:APPID
 //    appId:APPID
 //    nonceStr:随即字符串
 //    nonceStr:随即字符串