Go語言對接微信支付與退款指南(示例詳解)
在互聯(lián)網(wǎng)技術(shù)日益發(fā)展的今天,線上支付已成為不可或缺的一部分。作為一門簡潔高效的編程語言,Go(又稱Golang)憑借其強大的并發(fā)處理能力和高效性能,在后端開發(fā)領(lǐng)域越來越受到開發(fā)者的青睞。本文將詳細(xì)介紹如何使用Go語言對接微信支付,并實現(xiàn)支付和退款功能,幫助開發(fā)者快速上手。
一、準(zhǔn)備工作
在開始編寫代碼之前,你需要先準(zhǔn)備好以下幾項工作:
- 注冊成為微信支付商戶:如果你還沒有微信支付商戶賬號,需要先前往微信支付商戶平臺完成注冊。
- 獲取必要的配置信息:
- 商戶號 (
MchId
) - AppID (
Appid
) - API v3 密鑰 (
ApiV3Key
) - 商戶證書序列號 (
MchSerialNo
) - 私鑰 (
PrivateKey
) - 支付通知地址 (
NotifyUrl
) - 退款通知地址 (
RefundUrl
)
- 商戶號 (
安裝第三方庫:為了簡化微信支付接口的調(diào)用,推薦使用github.com/go-pay/gopay
這個庫??梢酝ㄟ^go get
命令安裝:
go get github.com/go-pay/gopay
二、初始化微信支付客戶端
首先,我們需要創(chuàng)建一個WechatPayService
結(jié)構(gòu)體來封裝微信支付的相關(guān)操作。該結(jié)構(gòu)體包含上下文、配置信息和微信支付客戶端實例。
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
函數(shù)來初始化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密鑰和私鑰等關(guān)鍵參數(shù)。為了保障支付的安全性,開啟了自動驗簽功能。
三、實現(xiàn)支付功能
1. 付款時序圖
2. 實現(xiàn)不同場景下的支付
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支付很像。主要區(qū)別在于app與商戶服務(wù)后臺的交互。app會從商戶服務(wù)后臺獲取簽名信息,根據(jù)簽名信息,app直接調(diào)用微信支付服務(wù)下單。
3. 解析支付回調(diào)
當(dāng)用戶完成支付后,微信會向我們的服務(wù)器發(fā)送支付成功的回調(diào)通知。我們需要解析這個通知并驗證其合法性。
func (w *WechatPayService) GetNotifyResult(r *http.Request) (res *wechat.V3DecryptResult, err error) { notifyReq, err := wechat.V3ParseNotify(r) // 解析回調(diào)參數(shù) if err != nil { fmt.Println(err) return } if notifyReq == nil { return } return notifyReq.DecryptCipherText(w.config.ApiV3Key) // 解密回調(diào)內(nèi)容 }
通過V3ParseNotify
方法,解析支付通知,并使用API v3密鑰解密支付結(jié)果。
四、實現(xiàn)退款功能
退款時序圖
發(fā)起退款
除了支付,退款也是微信支付中常用的功能。接下來,我們來看如何使用Go語言實現(xiàn)退款功能。
當(dāng)需要對已支付的訂單進行退款時,可以調(diào)用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) // 發(fā)起退款請求 if err != nil { return } if rsp == nil || rsp.Response == nil || rsp.Error != "" { // 處理退款錯誤 err = errors.New(rsp.Error) return } return }
解析退款回調(diào)
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) }
五、總結(jié)
通過本文的介紹,相信你已經(jīng)掌握了如何使用Go語言對接微信支付,并實現(xiàn)了支付和退款功能。這些功能不僅能夠提升用戶體驗,還能幫助你在實際項目中更加高效地處理支付相關(guān)的業(yè)務(wù)邏輯。希望本文對你有所幫助!
到此這篇關(guān)于Go語言對接微信支付與退款全流程指南的文章就介紹到這了,更多相關(guān)Go語言對接微信支付與退款內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏的解決方案詳解
這篇文章主要為大家詳細(xì)介紹了當(dāng)Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏時蓋如何解決,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-07-07一文掌握Golang的panic和recover實戰(zhàn)
Go語言中,異常處理通常依賴error返回值,本文將通過示例展示如何在Go語言中正確使用recover來處理panic異常,防止程序直接崩潰,感興趣的朋友跟隨小編一起看看吧2024-09-09