golang实现微信小程序支付服务端

前端之家收集整理的这篇文章主要介绍了golang实现微信小程序支付服务端前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

小程序支付的交互图如下:

小程序支付时序图

商户系统和微信支付系统主要交互:
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 WXPayResp struct {
    Return_code string `xml:"return_code"`
    Return_msg  string `xml:"return_msg"`
    Nonce_str   string `xml:"nonce_str"`
    Prepay_id   string `xml:"prepay_id"`
}
//微信支付
func (index *IndexController) WxPay(){
    info := make(map[string]interface{}, 0)

    fmt.Println("访问ip",index.Request.RemoteAddr)
    ip := utils.Substr(index.Request.RemoteAddr, 0,strings.Index(index.Request.RemoteAddr,":"))

    total_fee,_ := strconv.ParseFloat(index.GetString("total_fee"),64)  //单位 分
    openId := index.GetString("openId");        //"oKYr_0GkE-Izt9N9Wn43sapI9Pqw"
    body := "费用说明";
    //订单号
    orderNo := index.GetString("orderNo"); //"wx"+utils.ToStr(time.Now().Unix()) + string(utils.Krand(4,0))
    //随机
    nonceStr := time.Now().Format("20060102150405") + string(utils.Krand(4, 0))
    var reqMap = make(map[string]interface{}, 0)
    reqMap["appid"] = utils.Wx_Appid//微信小程序appid
    reqMap["body"] = body           //商品描述
    reqMap["mch_id"] = utils.Wx_Mchid   //商户号
    reqMap["nonce_str"] = nonceStr      //随机
    reqMap["notify_url"] = "http://test.com.cn/weixinNotice.jspx"   //通知地址
    reqMap["openid"] = openId       //商户唯一标识 openid
    reqMap["out_trade_no"] = orderNo    //订单号
    reqMap["spbill_create_ip"] = ip     //用户端ip //订单生成的机器 IP
    reqMap["total_fee"] = total_fee * 100   //订单总金额,单位为分
    reqMap["trade_type"] = "JSAPI"      //trade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识
    reqMap["sign"] = WxPayCalcSign(reqMap,utils.WX_KEY)

    reqStr := Map2Xml(reqMap)
    fmt.Println("请求xml",reqStr)

    client := &http.Client{}

    // 调用支付统一下单API
    req,err := http.NewRequest("POST","https://api.mch.weixin.qq.com/pay/unifiedorder",strings.NewReader(reqStr))
    if err != nil {
        // handle error
    }
    req.Header.Set("Content-Type","text/xml;charset=utf-8")

    resp,err := client.Do(req)
    defer resp.Body.Close()

    body2,err := IoUtil.ReadAll(resp.Body)
    if err != nil {
        // handle error
        fmt.Println("解析响应内容失败",err)
        return
    }
    fmt.Println("响应数据",string(body2))

    var resp1 WXPayResp
    err = xml.Unmarshal(body2,&resp1)
    if err != nil {
        panic(err)
        return
    }

    // 返回预付单信息
    if strings.ToUpper(resp1.Return_code) == "SUCCESS"{
        fmt.Println("预支付申请成功")
        // 再次签名
        var resMap = make(map[string]interface{}, 0)
        resMap["appId"] = utils.Wx_Appid
        resMap["nonceStr"] = resp1.Nonce_str            //商品描述
        resMap["package"] = "prepay_id=" + resp1.Prepay_id  //商户号
        resMap["signType"] = "MD5"              //签名类型
        resMap["timeStamp"] = utils.ToStr(time.Now().Unix())    //当前时间戳

        resMap["paySign"] = WxPayCalcSign(resMap,utils.WX_KEY)
        // 返回5个支付参数及sign 用户进行确认支付

        fmt.Println("支付参数",resMap)
        index.Console(resMap)
    }else{
        info["msg"] = "微信请求支付失败"
        index.Console(info)
    }
}
//微信支付计算签名的函数
func WxPayCalcSign(mReq map[string]interface{},key string) (sign string) {
    //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
    }

    fmt.Println("加密前-----",signStrings)
    //STEP4,进行MD5签名并且将所有字符转为大写.
    md5Ctx := md5.New()
    md5Ctx.Write([]byte(signStrings)) //
    cipherStr := md5Ctx.Sum(nil)
    upperSign := strings.ToUpper(hex.EncodeToString(cipherStr))

    fmt.Println("加密后-----",upperSign)
    return upperSign
}
//微信支付计算签名的函数
func Map2Xml(mReq map[string]interface{}) (xml string) {
    sb := bytes.Buffer{}
    sb.WriteString("<xml>")
    for k,v := range mReq{
        sb.WriteString("<"+k+">"+utils.ToStr(v)+"</"+k+">")
    }
    sb.WriteString("</xml>")
    return sb.String()
}

猜你在找的Go相关文章