Go語(yǔ)言對(duì)接微信支付與退款指南(示例詳解)
在互聯(lián)網(wǎng)技術(shù)日益發(fā)展的今天,線上支付已成為不可或缺的一部分。作為一門簡(jiǎn)潔高效的編程語(yǔ)言,Go(又稱Golang)憑借其強(qiáng)大的并發(fā)處理能力和高效性能,在后端開(kāi)發(fā)領(lǐng)域越來(lái)越受到開(kāi)發(fā)者的青睞。本文將詳細(xì)介紹如何使用Go語(yǔ)言對(duì)接微信支付,并實(shí)現(xiàn)支付和退款功能,幫助開(kāi)發(fā)者快速上手。
一、準(zhǔn)備工作
在開(kāi)始編寫(xiě)代碼之前,你需要先準(zhǔn)備好以下幾項(xiàng)工作:
- 注冊(cè)成為微信支付商戶:如果你還沒(méi)有微信支付商戶賬號(hào),需要先前往微信支付商戶平臺(tái)完成注冊(cè)。
- 獲取必要的配置信息:
- 商戶號(hào) (
MchId) - AppID (
Appid) - API v3 密鑰 (
ApiV3Key) - 商戶證書(shū)序列號(hào) (
MchSerialNo) - 私鑰 (
PrivateKey) - 支付通知地址 (
NotifyUrl) - 退款通知地址 (
RefundUrl)
- 商戶號(hào) (
安裝第三方庫(kù):為了簡(jiǎn)化微信支付接口的調(diào)用,推薦使用github.com/go-pay/gopay這個(gè)庫(kù)。可以通過(guò)go get命令安裝:
go get github.com/go-pay/gopay
二、初始化微信支付客戶端
首先,我們需要?jiǎng)?chuàng)建一個(gè)WechatPayService結(jié)構(gòu)體來(lái)封裝微信支付的相關(guān)操作。該結(jié)構(gòu)體包含上下文、配置信息和微信支付客戶端實(shí)例。
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
}接著,我們通過(guò)NewWechatPayService函數(shù)來(lái)初始化WechatPayService實(shí)例。
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,
}
}此代碼段中,我們通過(guò)NewClientV3方法初始化了微信支付客戶端,傳入商戶號(hào)、證書(shū)序列號(hào)、API v3密鑰和私鑰等關(guān)鍵參數(shù)。為了保障支付的安全性,開(kāi)啟了自動(dòng)驗(yàn)簽功能。
三、實(shí)現(xiàn)支付功能
1. 付款時(shí)序圖

2. 實(shí)現(xiàn)不同場(chǎng)景下的支付
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ù)后臺(tái)的交互。app會(huì)從商戶服務(wù)后臺(tái)獲取簽名信息,根據(jù)簽名信息,app直接調(diào)用微信支付服務(wù)下單。
3. 解析支付回調(diào)
當(dāng)用戶完成支付后,微信會(huì)向我們的服務(wù)器發(fā)送支付成功的回調(diào)通知。我們需要解析這個(gè)通知并驗(yàn)證其合法性。
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)容
}通過(guò)V3ParseNotify方法,解析支付通知,并使用API v3密鑰解密支付結(jié)果。
四、實(shí)現(xiàn)退款功能
退款時(shí)序圖

發(fā)起退款
除了支付,退款也是微信支付中常用的功能。接下來(lái),我們來(lái)看如何使用Go語(yǔ)言實(shí)現(xiàn)退款功能。
當(dāng)需要對(duì)已支付的訂單進(jìn)行退款時(shí),可以調(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ā)起退款請(qǐng)求
if err != nil {
return
}
if rsp == nil || rsp.Response == nil || rsp.Error != "" {
// 處理退款錯(cuò)誤
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é)
通過(guò)本文的介紹,相信你已經(jīng)掌握了如何使用Go語(yǔ)言對(duì)接微信支付,并實(shí)現(xiàn)了支付和退款功能。這些功能不僅能夠提升用戶體驗(yàn),還能幫助你在實(shí)際項(xiàng)目中更加高效地處理支付相關(guān)的業(yè)務(wù)邏輯。希望本文對(duì)你有所幫助!
到此這篇關(guān)于Go語(yǔ)言對(duì)接微信支付與退款全流程指南的文章就介紹到這了,更多相關(guān)Go語(yǔ)言對(duì)接微信支付與退款內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Go語(yǔ)言中獲取文件路徑的不同方法與應(yīng)用場(chǎng)景
在使用?Go?開(kāi)發(fā)項(xiàng)目時(shí),估計(jì)有不少人遇到過(guò)無(wú)法正確處理文件路徑的問(wèn)題,本文將嘗試從簡(jiǎn)單到復(fù)雜,詳細(xì)介紹?Go?中獲取路徑的不同方法及應(yīng)用場(chǎng)景,希望對(duì)大家有所幫助2024-02-02
Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏的解決方案詳解
這篇文章主要為大家詳細(xì)介紹了當(dāng)Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏時(shí)蓋如何解決,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-07-07
Go語(yǔ)言操作Excel的實(shí)現(xiàn)示例
excelize是一個(gè)功能豐富且易于使用的Go語(yǔ)言庫(kù),它極大地簡(jiǎn)化了Excel文件的讀寫(xiě)操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-12-12
一文掌握Golang的panic和recover實(shí)戰(zhàn)
Go語(yǔ)言中,異常處理通常依賴error返回值,本文將通過(guò)示例展示如何在Go語(yǔ)言中正確使用recover來(lái)處理panic異常,防止程序直接崩潰,感興趣的朋友跟隨小編一起看看吧2024-09-09
Go 協(xié)程超時(shí)控制的實(shí)現(xiàn)
本文主要介紹了Go 協(xié)程超時(shí)控制的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
GoFrame基于性能測(cè)試得知grpool使用場(chǎng)景
這篇文章主要為大家介紹了GoFrame基于性能測(cè)試得知grpool使用場(chǎng)景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Go語(yǔ)言break跳轉(zhuǎn)語(yǔ)句怎么使用
這篇文章主要介紹了Go語(yǔ)言break跳轉(zhuǎn)語(yǔ)句怎么使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01

