首页 > 上网技巧 > 电脑小技巧 > golang实现微信小程序支付服务端

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

时间:2018-04-08 09:16 作者:QQ地带 我要评论

小程序支付的交互图如下:
 
小程序支付时序图
 
 
 
商户系统和微信支付系统主要交互:
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()
}

标签: golang
顶一下
(0)
0%
踩一下
(0)
0%

Google提供的广告