golang实现微信小程序支付通知
来源:互联网 发布:宾馆记账软件 编辑:程序博客网 时间:2024/06/14 12:24
小程序支付的交互图如下:
小程序支付时序图
商户系统和微信支付系统主要交互:1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】2、商户server调用支付统一下单,api参见公共api【统一下单API】3、商户server调用再次签名,api参见公共api【再次签名】4、商户server接收支付通知,api参见公共api【支付结果通知API】5、商户server查询支付结果,api参见公共api【查询订单API】
以下是支付结果通知API
type WXPayNotifyReq struct { Appid string `xml:"appid"` Bank_type string `xml:"bank_type"` Cash_fee float64 `xml:"cash_fee"` Fee_type string `xml:"fee_type"` Is_subscribe string `xml:"is_subscribe"` Mch_id string `xml:"mch_id"` Nonce_str string `xml:"nonce_str"` Openid string `xml:"openid"` Out_trade_no string `xml:"out_trade_no"` Result_code string `xml:"result_code"` Return_code string `xml:"return_code"` Sign string `xml:"sign"` Time_end string `xml:"time_end"` Total_fee float64 `xml:"total_fee"` Trade_type string `xml:"trade_type"` Transaction_id string `xml:"transaction_id"`}type WXPayNotifyResp struct { Return_code string `xml:"return_code"` Return_msg string `xml:"return_msg"`}
/** * 微信通知接口 */func WeixinNoticeHandler(rw http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) if err != nil { logger.Error("读取http body失败,原因!", err) http.Error(rw.(http.ResponseWriter), http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } defer req.Body.Close() logger.Info("微信支付异步通知,HTTP Body:", string(body)) var mr WXPayNotifyReq err = xml.Unmarshal(body, &mr) if err != nil { logger.Error("解析HTTP Body格式到xml失败,原因!", err) http.Error(rw.(http.ResponseWriter), http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } var reqMap map[string]interface{} reqMap = make(map[string]interface{}, 0) reqMap["appid"] = mr.Appid reqMap["bank_type"] = mr.Bank_type reqMap["cash_fee"] = mr.Cash_fee reqMap["fee_type"] = mr.Fee_type reqMap["is_subscribe"] = mr.Is_subscribe reqMap["mch_id"] = mr.Mch_id reqMap["nonce_str"] = mr.Nonce_str reqMap["openid"] = mr.Openid reqMap["out_trade_no"] = mr.Out_trade_no reqMap["result_code"] = mr.Result_code reqMap["return_code"] = mr.Return_code reqMap["time_end"] = mr.Time_end reqMap["total_fee"] = mr.Total_fee reqMap["trade_type"] = mr.Trade_type reqMap["transaction_id"] = mr.Transaction_id var resp WXPayNotifyResp //进行签名校验 if wxpayVerifySign(reqMap, mr.Sign) { //transactionId := reqMap["transaction_id"] orderCode := reqMap["out_trade_no"] total_fee := reqMap["total_fee"].(float64) //分->元 除以100 rows,err := mysqlDB.Query("SELECT * FROM canyin_order WHERE dno = ?",orderCode) if err!=nil{ logger.Error("微信查询价格错误", err) return } defer rows.Close() orders := RowResult(rows) if len(orders) > 0 { orderInfo := orders[0].(map[string]interface{}) //orderId := ToStr(orderInfo["id"]) allcost, _ := strconv.ParseFloat(ToStr(orderInfo["allcost"]), 64) logger.Info("价格比对","---",allcost,"---",total_fee) //商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失 if allcost == total_fee { logger.Info("订单验证成功") //以下是业务处理 } resp.Return_code = "SUCCESS" resp.Return_msg = "OK" }else{ resp.Return_code = "FAIL" resp.Return_msg = "无此订单" } }else { resp.Return_code = "FAIL" resp.Return_msg = "failed to verify sign, please retry!" } //结果返回,微信要求如果成功需要返回return_code "SUCCESS" bytes, _err := xml.Marshal(resp) //string(bytes) strResp := strings.Replace(bytes2str(bytes), "WXPayNotifyResp", "xml", -1) if _err != nil { logger.Error("xml编码失败,原因:", _err) http.Error(rw.(http.ResponseWriter), http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } rw.(http.ResponseWriter).WriteHeader(http.StatusOK) fmt.Fprint(rw.(http.ResponseWriter), strResp)}
//微信支付签名验证函数func wxpayVerifySign(needVerifyM map[string]interface{}, sign string) bool { //方法名 行数 pc, _, line, _ := runtime.Caller(0) fc := runtime.FuncForPC(pc) WECHAT_API_KEY := "" //微信商户key signCalc := wxpayCalcSign(needVerifyM, WECHAT_API_KEY) logger.Info(fc.Name(), line, "计算出来的sign: ", signCalc) logger.Info(fc.Name(), line, "微信异步通知sign: ", sign) if sign == signCalc { logger.Info(fc.Name(), line, "签名校验通过!") return true } logger.Error(fc.Name(), line, "签名校验失败!") return false}
//微信支付计算签名的函数func wxpayCalcSign(mReq map[string]interface{}, key string) (sign string) { //方法名 行数 pc, _, line, _ := runtime.Caller(0) fc := runtime.FuncForPC(pc) logger.Info(fc.Name(), line, "微信支付签名计算, API KEY:", key) //STEP 1, 对key进行升序排序. sorted_keys := make([]string, 0) for k, _ := range mReq { sorted_keys = append(sorted_keys, k) } sort.Strings(sorted_keys) //STEP2, 对key=value的键值对用&连接起来,略过空值 var signStrings string for _, k := range sorted_keys { logger.Printf("k=%v, v=%v\n", k, mReq[k]) value := fmt.Sprintf("%v", mReq[k]) if value != "" { signStrings = signStrings + k + "=" + value + "&" } } //STEP3, 在键值对的最后加上key=API_KEY if key != "" { signStrings = signStrings + "key=" + key } //STEP4, 进行MD5签名并且将所有字符转为大写. md5Ctx := md5.New() md5Ctx.Write(str2bytes(signStrings)) cipherStr := md5Ctx.Sum(nil) upperSign := strings.ToUpper(hex.EncodeToString(cipherStr)) return upperSign}
阅读全文
0 0
- golang实现微信小程序支付通知
- golang实现微信小程序支付服务端
- Golang实现Supervisor事件通知
- java实现微信小程序支付
- golang 实现 iOS http2 推送 Apns通知
- 推送通知,网络编程,程序内支付,第三方支付
- 微信小程序中实现微信支付
- 微信小程序支付c#后台实现
- 实现小程序支付
- 微信小程序之支付后调用SDK的异步通知及验证处理订单
- 如何使用golang实现微信支付的服务端
- 微信小程序通知服务实现及错误47001和41028
- 微信小程序Form通知
- Golang微信支付
- 4部分代码轻松实现微信小程序支付功能
- 微信小程序与内嵌网页交互实现支付功能
- 微信小程序-支付倒计时
- 微信小程序支付
- SCH自动标注器件号
- orcle 多表关联update
- 启动参数
- 一个疑问,模拟bootstrap获取webappclassloader的class却不成功,无语了。
- 容斥
- golang实现微信小程序支付通知
- 正则匹配简介
- ubuntu 下 docker 的container不能联网的问题
- Spring Bean加载(一)
- tomcat在conf/Catalina/localhost目录下配置虚拟目录
- httpurlconnectionget3
- 【脚本语言系列】关于Python基础知识多返回值,你需要知道的事
- include,require,include_once,require_once区别和性能对比
- 多年iOS开发经验总结(二)