Go语言对接微信支付与退款全流程指南

目录:
一、准备工作
二、初始化微信支付客户端
三、实现支付功能
1. 付款时序图
2. 实现不同场景下的支付
WAP端支付
PC端支付
Android端支付
3. 解析支付回调
四、实现退款功能
退款时序图
发起退款
解析退款回调
五、总结

在互联网技术日益发展的今天,线上支付已成为不可或缺的一部分。作为一门简洁高效的编程语言,Go(又称Golang)凭借其强大的并发处理能力和高效性能,在后端开发领域越来越受到开发者的青睐。本文将详细介绍如何使用Go语言对接微信支付,并实现支付和退款功能,帮助开发者快速上手。

一、准备工作

在开始编写代码之前,你需要先准备好以下几项工作:

  1. 注册成为微信支付商户:如果你还没有微信支付商户账号,需要先前往微信支付商户平台完成注册。
  2. 获取必要的配置信息
    • 商户号 (MchId)
    • AppID (Appid)
    • API v3 密钥 (ApiV3Key)
    • 商户证书序列号 (MchSerialNo)
    • 私钥 (PrivateKey)
    • 支付通知地址 (NotifyUrl)
    • 退款通知地址 (RefundUrl)
  3. 安装第三方库:为了简化微信支付接口的调用,推荐使用github.com/go-pay/gopay这个库。可以通过go get命令安装:
    go get github.com/go-pay/gopay 

二、初始化微信支付客户端

首先,我们需要创建一个WechatPayService结构体来封装微信支付的相关操作。该结构体包含上下文、配置信息和微信支付客户端实例。

type WechatPayService struct { 	ctx       context.Context 	config    WechatPayConfig 	wechatPay *wechat.ClientV3 }  type WechatPayConfig struct { 	Appid       string 	Appid1      string 	MchId       string 	ApiV3Key    string 	MchSerialNo string 	PrivateKey  string 	NotifyUrl   string 	RefundUrl   string } 

接着,我们通过NewWechatPayService函数来初始化WechatPayService实例。

func NewWechatPayService(ctx context.Context, config WechatPayConfig) *WechatPayService { 	client, err := wechat.NewClientV3(config.MchId, config.MchSerialNo, config.ApiV3Key, config.PrivateKey) 	if err != nil { 		fmt.Println(err) 		return nil 	} 	err = client.AutoVerifySign() 	if err != nil { 		fmt.Println(err) 		return nil 	} 	client.DebugSwitch = gopay.DebugOn  	return &WechatPayService{ 		ctx:       ctx, 		wechatPay: client, 		config:    config, 	} } 

此代码段中,我们通过NewClientV3方法初始化了微信支付客户端,传入商户号、证书序列号、API v3密钥和私钥等关键参数。为了保障支付的安全性,开启了自动验签功能。

三、实现支付功能

1. 付款时序图

Go语言对接微信支付与退款全流程指南

2. 实现不同场景下的支付

WAP端支付

func (w *WechatPayService) WapPay(charge *Charge) (result string, err error) { 	amount := decimal.NewFromInt(charge.MoneyFee).DivRound(decimal.NewFromInt(1), 2).IntPart() 	expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339) 	bm := make(gopay.BodyMap) 	bm.Set("appid", w.config.Appid). 		Set("mchid", w.config.MchId). 		Set("description", charge.Describe). 		Set("out_trade_no", charge.TradeNum). 		Set("time_expire", expire). 		Set("notify_url", w.config.NotifyUrl). 		SetBodyMap("amount", func(bm gopay.BodyMap) { 			bm.Set("total", amount). 				Set("currency", "CNY") 		}). 		SetBodyMap("scene_info", func(bm gopay.BodyMap) { 			bm.Set("payer_client_ip", "127.0.0.1"). 				SetBodyMap("h5_info", func(bm gopay.BodyMap) { 					bm.Set("type", "Wap") 				}) 		})  	rsp, err := w.wechatPay.V3TransactionH5(w.ctx, bm) 	if err != nil { 		return 	} 	result = rsp.Response.H5Url 	return } 

PC端支付

func (w *WechatPayService) PcPay(charge *Charge) (result string, err error) { 	amount := decimal.NewFromInt(charge.MoneyFee).DivRound(decimal.NewFromInt(1), 2).IntPart() 	expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339) 	bm := make(gopay.BodyMap) 	bm.Set("appid", w.config.Appid). 		Set("mchid", w.config.MchId). 		Set("description", charge.Describe). 		Set("out_trade_no", charge.TradeNum). 		Set("time_expire", expire). 		Set("notify_url", w.config.NotifyUrl). 		SetBodyMap("amount", func(bm gopay.BodyMap) { 			bm.Set("total", amount). 				Set("currency", "CNY") 		})  	rsp, err := w.wechatPay.V3TransactionNative(w.ctx, bm) 	if err != nil { 		return 	} 	result = rsp.Response.CodeUrl 	return } 

Android端支付

func (w *WechatPayService) AndroidPay(charge *Charge) (result string, err error) { 	amount := decimal.NewFromInt(charge.MoneyFee).DivRound(decimal.NewFromInt(1), 2).IntPart() 	expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339) 	bm := make(gopay.BodyMap) 	bm.Set("appid", w.config.Appid1). 		Set("mchid", w.config.MchId). 		Set("description", charge.Describe). 		Set("out_trade_no", charge.TradeNum). 		Set("time_expire", expire). 		Set("notify_url", w.config.NotifyUrl). 		SetBodyMap("amount", func(bm gopay.BodyMap) { 			bm.Set("total", amount). 				Set("currency", "CNY") 		})  	rsp, err := w.wechatPay.V3TransactionApp(w.ctx, bm)  	if err != nil { 		return 	}  	jsapiInfo, err := w.wechatPay.PaySignOfApp(w.config.Appid1, rsp.Response.PrepayId) 	str, _ := json.Marshal(jsapiInfo) 	result = string(str) 	return } 
  • APP支付跟JSAPI支付很像。主要区别在于app与商户服务后台的交互。app会从商户服务后台获取签名信息,根据签名信息,app直接调用微信支付服务下单。

3. 解析支付回调

当用户完成支付后,微信会向我们的服务器发送支付成功的回调通知。我们需要解析这个通知并验证其合法性。

func (w *WechatPayService) GetNotifyResult(r *http.Request) (res *wechat.V3DecryptResult, err error) { 	notifyReq, err := wechat.V3ParseNotify(r)    // 解析回调参数 	if err != nil { 		fmt.Println(err) 		return 	} 	if notifyReq == nil { 		return 	} 	return notifyReq.DecryptCipherText(w.config.ApiV3Key)  // 解密回调内容 } 

通过V3ParseNotify方法,解析支付通知,并使用API v3密钥解密支付结果。

四、实现退款功能

退款时序图

Go语言对接微信支付与退款全流程指南

发起退款

除了支付,退款也是微信支付中常用的功能。接下来,我们来看如何使用Go语言实现退款功能。

当需要对已支付的订单进行退款时,可以调用Refund方法。

func (w *WechatPayService) Refund(charge *RefundCharge) (err error) { 	amount := decimal.NewFromInt(charge.MoneyFee).DivRound(decimal.NewFromInt(1), 2).IntPart() 	bm := make(gopay.BodyMap) 	bm.Set("out_trade_no", charge.TradeNum). 		Set("out_refund_no", charge.OutRefundNo). 		Set("reason", charge.RefundReason). 		Set("notify_url", w.config.RefundUrl). 		SetBodyMap("amount", func(bm gopay.BodyMap) { 			bm.Set("total", amount). 				Set("refund", amount). 				Set("currency", "CNY") 		})  	rsp, err := w.wechatPay.V3Refund(w.ctx, bm)  // 发起退款请求 	if err != nil { 		return 	}  	if rsp == nil || rsp.Response == nil || rsp.Error != "" {         // 处理退款错误 		err = errors.New(rsp.Error)  		return 	} 	return } 

解析退款回调

func (w *WechatPayService) GetRefundNotifyResult(r *http.Request) (res *wechat.V3DecryptRefundResult, err error) { 	notifyReq, err := wechat.V3ParseNotify(r) 	if err != nil { 		return 	} 	return notifyReq.DecryptRefundCipherText(w.config.ApiV3Key) } 

五、总结

通过本文的介绍,相信你已经掌握了如何使用Go语言对接微信支付,并实现了支付和退款功能。这些功能不仅能够提升用户体验,还能帮助你在实际项目中更加高效地处理支付相关的业务逻辑。希望本文对你有所帮助!

如果你有任何问题或建议,欢迎在评论区留言交流。期待你的宝贵意见!
Go语言对接微信支付与退款全流程指南

发表评论

评论已关闭。

相关文章