go 微信支付开发 jsapi
一、准备工作
1 . 注册企业账号: https://pay.weixin.qq.com/
2 . 配置V3 支付
3 . 绑定微信小程序
4 . 设置 下载证书
5 . 也可以手撸文档 https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/direct-jsons/jsapi-prepay.html
二、证书放在项目 cert中
image-20231010171100268.png
三、配置config.yml
1 . 注册企业账号: https://pay.weixin.qq.com/
2 . 配置V3 支付
3 . 绑定微信小程序
4 . 设置 下载证书
5 . 也可以手撸文档 https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/direct-jsons/jsapi-prepay.html
四、下载对应的SDK
go get github.com/wechatpay-apiv3/wechatpay-go
五、封装微信支付类 pay.go
package wepay
//支付公共uri
const (
publicKeyUrl = "https://api.mch.weixin.qq.com/v3/certificates"
commonPayUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"
)
//自定义回调uri
const (
notifyUrl = "https://xxxxxxx/api/v1/order/notify"
)
// 微信支付
func JsApi(payResMap map[string]string) (payJson map[string]string, err error) {
appId := viper.GetString("mini.appId")
privatePath := viper.GetString("wePay.privatePath")
payMap := make(map[string]string)
timeStamp := time.Now().Unix()
nonce := waymon.GetRandomString(32)
packageStr := "prepay_id=" + payResMap["prepay_id"]
payMap["appId"] = appId
payMap["timeStamp"] = fmt.Sprintf("%v", timeStamp)
payMap["nonceStr"] = nonce
payMap["package"] = packageStr
// 签名
message := fmt.Sprintf("%s\n%s\n%s\n%s\n", appId, fmt.Sprintf("%v", timeStamp), nonce, packageStr)
dir, _ := os.Getwd()
open, err := os.Open(dir + privatePath)
if err != nil {
return payJson, err
}
defer open.Close()
privateKey, err := ioutil.ReadAll(open)
if err != nil {
return payJson, err
}
signBytes, err := signPKCS1v15(hasha256(message), privateKey, crypto.SHA256)
if err != nil {
return payJson, err
}
sign := base64EncodeStr(signBytes)
payMap["signType"] = "RSA"
payMap["paySign"] = sign
payJsonBytes, err := json.Marshal(payMap)
if err != nil {
return payJson, err
}
err = json.Unmarshal(payJsonBytes, &payJson)
if err != nil {
return nil, err
}
return payJson, nil
}
func CommonPay(tradeNo, desc, openId string, amount int) (payResMap map[string]string, err error) {
appId := viper.GetString("mini.appId")
mchId := viper.GetString("wePay.mchId")
payResMap = make(map[string]string)
paramMap := make(map[string]interface{})
paramMap["appid"] = appId
paramMap["mchid"] = mchId
paramMap["description"] = desc
paramMap["out_trade_no"] = tradeNo
paramMap["notify_url"] = notifyUrl
paramMap["amount"] = map[string]interface{}{
"total": amount,
"currency": "CNY",
}
paramMap["payer"] = map[string]string{
"openid": openId,
}
token, err := authorization(http.MethodPost, paramMap, commonPayUrl)
if err != nil {
return payResMap, err
}
marshal, _ := json.Marshal(paramMap)
request, err := http.NewRequest(http.MethodPost, commonPayUrl, bytes.NewReader(marshal))
if err != nil {
return payResMap, err
}
request.Header.Add("Authorization", "WECHATPAY2-SHA256-RSA2048 "+token)
request.Header.Add("User-Agent", "用户代理(https://zh.wikipedia.org/wiki/User_agent)")
request.Header.Add("Content-type", "application/json;charset='utf-8'")
request.Header.Add("Accept", "application/json")
client := http.DefaultClient
response, err := client.Do(request)
if err != nil {
return payResMap, err
}
defer func() {
response.Body.Close()
}()
bodyBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return payResMap, err
}
if err = json.Unmarshal(bodyBytes, &payResMap); err != nil {
return payResMap, err
}
if payResMap["prepay_id"] == "" {
return payResMap, errors.New("code:" + payResMap["code"] + "err:" + payResMap["message"])
}
return payResMap, nil
}
六、调用方法
payRes, err := wepay.CommonPay(service.TradeNo, service.Desc, service.OpenId, service.Money)
if err != nil {
code = e.Error
return res.Response{
Status: code,
Msg: err.Error(),
Data: nil,
}
}
pay, err := wepay.JsApi(payRes)
if err != nil {
code = e.Error
return res.Response{
Status: code,
Msg: err.Error(),
Data: nil,
}
}
pay : 返回给前端小程序调起支付
七、回调
func OrderNotify(c *gin.Context) {
aesKey := viper.GetString("wePay.aesKey")
defer func() {
//错误处理
if e := recover(); e != nil {
zap.S().Error("微信支付回调异常:", e)
log.Logger.Error("微信支付回调异常")
}
}()
request := notify.Request{}
c.ShouldBind(&request)
mapstructure.Decode(c.Params, &request)
if request.EventType == "TRANSACTION.SUCCESS" {
plaintext, err := wepay.DecryptAES256GCM(
aesKey, request.Resource.AssociatedData, request.Resource.Nonce, request.Resource.Ciphertext,
)
if err != nil {
fmt.Println(err)
zap.S().Error("DecryptAES256GCM err" + err.Error())
log.Logger.Error("DecryptAES256GCM err" + err.Error())
}
transaction := payments.Transaction{}
json.Unmarshal([]byte(plaintext), &transaction)
go func() {
// 执行service层代码
}()
tmp := make(map[string]interface{})
tmp["code"] = "SUCCESS"
tmp["message"] = "成功"
tmpJson, _ := json.Marshal(tmp)
c.Writer.Write(tmpJson)
} else {
tmp := make(map[string]interface{})
tmp["code"] = "500"
tmp["message"] = "失败"
tmpJson, _ := json.Marshal(tmp)
c.Writer.Write(tmpJson)
}
}
八、代码
https://github.com/Waymon102092/WaymonWeXinPay
eg
github主页: https://github.com/Waymon102092/
微信公众号: Waymon