golang实现微信小程序支付通知

前端之家收集整理的这篇文章主要介绍了golang实现微信小程序支付通知前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

小程序支付的交互图如下:

小程序支付时序图

  1. 商户系统和微信支付系统主要交互:
  2. 1小程序调用登录接口,获取用户openid,api参见公共api小程序登录API
  3. 2、商户server调用支付统一下单,api参见公共api【统一下单API
  4. 3、商户server调用再次签名,api参见公共api【再次签名】
  5. 4、商户server接收支付通知api参见公共api【支付结果通知API
  6. 5、商户server查询支付结果,api参见公共api查询订单API

以下是支付结果通知API

  1. type WXPayNotifyReq struct {
  2. Appid string `xml:"appid"`
  3. Bank_type string `xml:"bank_type"`
  4. Cash_fee float64 `xml:"cash_fee"`
  5. Fee_type string `xml:"fee_type"`
  6. Is_subscribe string `xml:"is_subscribe"`
  7. Mch_id string `xml:"mch_id"`
  8. Nonce_str string `xml:"nonce_str"`
  9. Openid string `xml:"openid"`
  10. Out_trade_no string `xml:"out_trade_no"`
  11. Result_code string `xml:"result_code"`
  12. Return_code string `xml:"return_code"`
  13. Sign string `xml:"sign"`
  14. Time_end string `xml:"time_end"`
  15. Total_fee float64 `xml:"total_fee"`
  16. Trade_type string `xml:"trade_type"`
  17. Transaction_id string `xml:"transaction_id"`
  18. }
  19.  
  20.  
  21. type WXPayNotifyResp struct {
  22. Return_code string `xml:"return_code"`
  23. Return_msg string `xml:"return_msg"`
  24. }
  1. /** * 微信通知接口 */
  2. func WeixinNoticeHandler(rw http.ResponseWriter,req *http.Request) {
  3. body,err := IoUtil.ReadAll(req.Body)
  4. if err != nil {
  5. logger.Error("读取http body失败,原因!",err)
  6. http.Error(rw.(http.ResponseWriter),http.StatusText(http.StatusBadRequest),http.StatusBadRequest)
  7. return
  8. }
  9. defer req.Body.Close()
  10. logger.Info("微信支付异步通知,HTTP Body:",string(body))
  11.  
  12. var mr WXPayNotifyReq
  13. err = xml.Unmarshal(body,&mr)
  14. if err != nil {
  15. logger.Error("解析HTTP Body格式到xml失败,原因!",http.StatusBadRequest)
  16. return
  17. }
  18.  
  19. var reqMap map[string]interface{}
  20. reqMap = make(map[string]interface{},0)
  21.  
  22. reqMap["appid"] = mr.Appid
  23. reqMap["bank_type"] = mr.Bank_type
  24. reqMap["cash_fee"] = mr.Cash_fee
  25. reqMap["fee_type"] = mr.Fee_type
  26. reqMap["is_subscribe"] = mr.Is_subscribe
  27. reqMap["mch_id"] = mr.Mch_id
  28. reqMap["nonce_str"] = mr.Nonce_str
  29. reqMap["openid"] = mr.Openid
  30. reqMap["out_trade_no"] = mr.Out_trade_no
  31. reqMap["result_code"] = mr.Result_code
  32. reqMap["return_code"] = mr.Return_code
  33. reqMap["time_end"] = mr.Time_end
  34. reqMap["total_fee"] = mr.Total_fee
  35. reqMap["trade_type"] = mr.Trade_type
  36. reqMap["transaction_id"] = mr.Transaction_id
  37.  
  38. var resp WXPayNotifyResp
  39. //进行签名校验
  40. if wxpayVerifySign(reqMap,mr.Sign) {
  41. //transactionId := reqMap["transaction_id"]
  42. orderCode := reqMap["out_trade_no"]
  43. total_fee := reqMap["total_fee"].(float64) //分->元 除以100
  44. rows,err := MysqLDB.Query("SELECT * FROM canyin_order WHERE dno = ?",orderCode)
  45. if err!=nil{
  46. logger.Error("微信查询价格错误",err)
  47. return
  48. }
  49. defer rows.Close()
  50. orders := RowResult(rows)
  51. if len(orders) > 0 {
  52. orderInfo := orders[0].(map[string]interface{})
  53. //orderId := ToStr(orderInfo["id"])
  54. allcost,_ := strconv.ParseFloat(ToStr(orderInfo["allcost"]),64)
  55. logger.Info("价格比对","---",allcost,total_fee)
  56. //商户系统对于支付结果通知内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失
  57. if allcost == total_fee {
  58. logger.Info("订单验证成功")
  59. //以下是业务处理
  60. }
  61. resp.Return_code = "SUCCESS"
  62. resp.Return_msg = "OK"
  63. }else{
  64. resp.Return_code = "FAIL"
  65. resp.Return_msg = "无此订单"
  66. }
  67. }else {
  68. resp.Return_code = "FAIL"
  69. resp.Return_msg = "Failed to verify sign,please retry!"
  70. }
  71.  
  72. //结果返回,微信要求如果成功需要返回return_code "SUCCESS"
  73. bytes,_err := xml.Marshal(resp) //string(bytes)
  74. strResp := strings.Replace(bytes2str(bytes),"WXPayNotifyResp","xml",-1)
  75. if _err != nil {
  76. logger.Error("xml编码失败,原因:",_err)
  77. http.Error(rw.(http.ResponseWriter),http.StatusBadRequest)
  78. return
  79. }
  80. rw.(http.ResponseWriter).WriteHeader(http.StatusOK)
  81. fmt.Fprint(rw.(http.ResponseWriter),strResp)
  82. }
  1. //微信支付签名验证函数
  2. func wxpayVerifySign(needVerifyM map[string]interface{},sign string) bool {
  3. //方法名 行数
  4. pc,_,line,_ := runtime.Caller(0)
  5. fc := runtime.FuncForPC(pc)
  6.  
  7. WECHAT_API_KEY := "" //微信商户key
  8. signCalc := wxpayCalcSign(needVerifyM,WECHAT_API_KEY)
  9. logger.Info(fc.Name(),"计算出来的sign: ",signCalc)
  10. logger.Info(fc.Name(),"微信异步通知sign: ",sign)
  11. if sign == signCalc {
  12. logger.Info(fc.Name(),"签名校验通过!")
  13. return true
  14. }
  15.  
  16. logger.Error(fc.Name(),"签名校验失败!")
  17. return false
  18. }
  1. //微信支付计算签名的函数
  2. func wxpayCalcSign(mReq map[string]interface{},key string) (sign string) {
  3. //方法名 行数
  4. pc,_,line,_ := runtime.Caller(0)
  5. fc := runtime.FuncForPC(pc)
  6.  
  7. logger.Info(fc.Name(),"微信支付签名计算,API KEY:",key)
  8. //STEP 1,对key进行升序排序.
  9. sorted_keys := make([]string,0)
  10. for k,_ := range mReq { sorted_keys = append(sorted_keys,k) }
  11.  
  12. sort.Strings(sorted_keys)
  13.  
  14. //STEP2,对key=value的键值对用&连接起来,略过空值
  15. var signStrings string
  16. for _,k := range sorted_keys {
  17. logger.Printf("k=%v,v=%v\n",k,mReq[k])
  18. value := fmt.Sprintf("%v",mReq[k])
  19. if value != "" {
  20. signStrings = signStrings + k + "=" + value + "&"
  21. }
  22. }
  23.  
  24. //STEP3,在键值对的最后加上key=API_KEY
  25. if key != "" {
  26. signStrings = signStrings + "key=" + key
  27. }
  28.  
  29. //STEP4,进行MD5签名并且将所有字符转为大写.
  30. md5Ctx := md5.New()
  31. md5Ctx.Write(str2bytes(signStrings))
  32. cipherStr := md5Ctx.Sum(nil)
  33. upperSign := strings.ToUpper(hex.EncodeToString(cipherStr))
  34. return upperSign
  35. }

猜你在找的Go相关文章