使用golang快速开发微信公众平台(五):公众号支付

u012210379 · · 5775 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

微信又TMD改版了

2个月前我做的一个微信公众号商城支付是正常的,但是同样的设置,目前做的这个却不正常了,老给我报invalid url domain,试遍了所有能找到的法子依然不行,卧槽他大爷,连写博客的欲望都没了,此坑待填。


跨过该死的设置,说下之前解决掉的2个问题:

  1. 微信安全设置要求服务器在你填写业务域名或js安全域名的位置,可以访问到一个MP_verify_xxxx.txt(之前无此硬性要求 我CNNND)
  2. 支付 而支付又分页面和后台

先说这个MP_verify_xxxx.txt咋办

直接说结果,beego框架有个缺点,不支持这么搞。比如我的域名是www.baidu.com,微信要求你,如果你这么填,就要求www.baidu.com/MP_verify_xxxx.txt能访问到,太悲催了。
2个解决办法:

  1. 不在根目录下,添加个2级目录,然后在main.go中设置beego.SetStaticPath("/wx_shop_cart", "mp")注意要写到beego.Run()之前
  2. 非得在根目录下,没其他可能,那可以这么搞:
beego.Router("/*", &controllers.MainController{})

先在main.go中这样写,同beego.Run()之前,然后在MainController中

func (c *MainController) Get() {

    orpath := c.Ctx.Request.URL.Path
    //fmt.Println("url : ", c.Ctx.Request.RequestURI)
    //fmt.Println("访问的路径中是否包含微信所要求的txt文本 : ", orpath)

    if strings.Index(orpath, "MP_verify_xxxx.txt") >= 0 {

        //path := filepath.Join(`static`, "MP_verify_xxxx.txt")
        //fmt.Println("path---------", path)
        //http.ServeFile(c.Ctx.ResponseWriter, c.Ctx.Request, path)
        c.Ctx.WriteString("txt文本中的内容")
    } else {
        c.TplName = "index.html"
    }
}

这样就OK了,简单粗暴有效。

该死的支付

先说后台代码

WXShopCartPayTestController

package controllers

import (
    "github.com/astaxie/beego"
    "fmt"
    "sort"
    "crypto/md5"
    "strings"
    "encoding/hex"
    "github.com/astaxie/beego/orm"
    "rbearserver/models"
    "rbearserver/shopUtils/logUtils"
    "crypto/sha1"
    "io"
)

/**
    订单付款 下单 提起请求
 */


type WXShopCartPayTestController struct {
    beego.Controller
}

//var uid string
func (c *WXShopCartPayTestController) Get() {

    //if uid != "" {
    //  fmt.Println("非正式支付接口-----------1")
    //  getShopCartForm(c)
    //} else {
    //  fmt.Println("WXShopCartPayTestController uid==空")
    //}
    c.TplName = "wx_shop_cart_pay_test.html"
}
func (c *WXShopCartPayTestController) Post() {

    c.EnableRender = false
    fmt.Println("WXShopCartPayTestController 接收微信支付订单结果--------------post")
    //微信支付回调函数 成功后跳转至订单页面
    //WxpayCallback(c.Ctx.ResponseWriter.ResponseWriter, c.Ctx.Request, c.Ctx)
}

//首先定义一个UnifyOrderReq用于填入我们要传入的参数。
type UnifyOrderReq struct {
    Appid            string `xml:"appid"`            //公众账号ID
    Body             string `xml:"body"`             //商品描述
    Mch_id           string `xml:"mch_id"`           //商户号
    Nonce_str        string `xml:"nonce_str"`        //随机字符串
    Notify_url       string `xml:"notify_url"`       //通知地址
    Trade_type       string `xml:"trade_type"`       //交易类型
    Spbill_create_ip string `xml:"spbill_create_ip"` //支付提交用户端ip
    Total_fee        int    `xml:"total_fee"`        //总金额
    Out_trade_no     string `xml:"out_trade_no"`     //商户订单号
    Sign             string `xml:"sign"`             //签名
    Openid           string `xml:"openid"`           //购买商品的用户wxid
}

//微信支付 下单签名
func wxpayCalcSign(mReq map[string]interface{}, key string) string {

    //fmt.Println("========STEP 1, 对key进行升序排序.========")
    //fmt.Println("微信支付签名计算, API KEY:", key)
    //STEP 1, 对key进行升序排序.
    sorted_keys := make([]string, 0)
    for k, _ := range mReq {
        sorted_keys = append(sorted_keys, k)
    }

    sort.Strings(sorted_keys)

    //fmt.Println("========STEP2, 对key=value的键值对用&连接起来,略过空值========")
    //STEP2, 对key=value的键值对用&连接起来,略过空值
    var signStrings string
    for _, k := range sorted_keys {
        //fmt.Printf("k=%v, v=%v\n", k, mReq[k])
        value := fmt.Sprintf("%v", mReq[k])
        if value != "" {
            signStrings = signStrings + k + "=" + value + "&"
        }
    }

    //fmt.Println("========STEP3, 在键值对的最后加上key=API_KEY========")
    //STEP3, 在键值对的最后加上key=API_KEY
    if key != "" {
        signStrings = signStrings + "key=" + key
    }

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

    return upperSign
}

type UnifyOrderResp struct {
    Return_code string `xml:"return_code"`
    Return_msg  string `xml:"return_msg"`
    Appid       string `xml:"appid"`
    Mch_id      string `xml:"mch_id"`
    Nonce_str   string `xml:"nonce_str"`
    Sign        string `xml:"sign"`
    Result_code string `xml:"result_code"`
    Prepay_id   string `xml:"prepay_id"`
    Trade_type  string `xml:"trade_type"`
}

//func getShopCartForm(c *WXShopCartPayTestController) {
//
//  fmt.Println("非正式支付接口-----------2")
//  orderid_str := c.GetString("orderid")
//  orderid, _ := strconv.Atoi(orderid_str)//订单id 根据此id可以查询good_order表获取商品及购买者信息
//  o := orm.NewOrm()
//  order := models.GoodOrder{Id:orderid}
//
//  if err := o.Read(&order, "id"); err == nil {
//
//      orderPrice, _ := strconv.ParseFloat(order.OrderValue, 64)
//      totalFee := int(orderPrice * 100)
//
//      //请求UnifiedOrder的代码
//      var yourReq UnifyOrderReq
//      yourReq.Appid = beego.AppConfig.String("APPID")
//      yourReq.Body = "mlshop-" + order.Goodname//浏览器打开的移动网页的主页title名-商品概述
//      yourReq.Mch_id = beego.AppConfig.String("shopKey")
//      yourReq.Nonce_str = RandomStrUtil.GetRandomString(32)
//      yourReq.Notify_url = "http://www.molan888.com/wx_shop_cart/payt/pay"
//      yourReq.Trade_type = "JSAPI"
//      yourReq.Spbill_create_ip = c.Ctx.Input.IP()
//      yourReq.Total_fee = totalFee // 单位是分 单位换为真实大小 注意要把元转换为分
//      yourReq.Openid = uid
//      yourReq.Out_trade_no = strconv.FormatInt(time.Now().Unix(), 10) + RandomStrUtil.GetRandomString(3)//订单号
//
//      var m map[string]interface{}
//      m = make(map[string]interface{}, 0)
//      m["appid"] = yourReq.Appid
//      m["body"] = yourReq.Body
//      m["mch_id"] = yourReq.Mch_id
//      m["notify_url"] = yourReq.Notify_url
//      m["trade_type"] = yourReq.Trade_type
//      m["spbill_create_ip"] = yourReq.Spbill_create_ip
//      m["total_fee"] = yourReq.Total_fee
//      m["out_trade_no"] = yourReq.Out_trade_no
//      m["nonce_str"] = yourReq.Nonce_str
//      m["openid"] = yourReq.Openid
//      yourReq.Sign = wxpayCalcSign(m, PAY_API_KEY) //这个key 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全
//
//      bytes_req, err := xml.Marshal(yourReq)
//      if err != nil {
//          fmt.Println("转换为xml错误:", err)
//          logUtils.GetLog().Error("转换为xml错误:", err)
//      }
//
//      str_req := strings.Replace(string(bytes_req), "UnifyOrderReq", "xml", -1)
//      //fmt.Println("转换为xml--------", str_req)
//
//      bytes_req = []byte(str_req)
//
//      //发送unified order请求.
//      req, err := http.NewRequest("POST", "https://api.mch.weixin.qq.com/pay/unifiedorder", bytes.NewReader(bytes_req))
//      if err != nil {
//          fmt.Println("New Http Request发生错误,原因:", err)
//          logUtils.GetLog().Error("New Http Request发生错误,原因:", err)
//          return
//
//      }
//      req.Header.Set("Accept", "application/xml")
//      //这里的http header的设置是必须设置的.
//      req.Header.Set("Content-Type", "application/xml;charset=utf-8")
//
//      client := http.Client{}
//      resp, _err := client.Do(req)
//      if _err != nil {
//          fmt.Println("请求微信支付统一下单接口发送错误, 原因:", _err)
//          logUtils.GetLog().Error("请求微信支付统一下单接口发送错误, 原因:", _err)
//          return
//      }
//
//      //------------------到这里统一下单接口就已经执行完成了-------------------
//
//      respBytes, err := ioutil.ReadAll(resp.Body)
//      if err != nil {
//          fmt.Println("解析返回body错误", err)
//          logUtils.GetLog().Error("解析返回body错误", err)
//          return
//      }
//      xmlResp := UnifyOrderResp{}
//      _err = xml.Unmarshal(respBytes, &xmlResp)
//      //处理return code.
//      if xmlResp.Return_code == "FAIL" {
//          fmt.Println("微信支付统一下单不成功,原因:", xmlResp.Return_msg, " str_req-->", str_req)
//          return
//      }
//
//      //这里已经得到微信支付的prepay id,需要返给客户端页面,由客户端继续完成支付流程

//      //向数据库存入 WxBill 订单号yourReq.Out_trade_no user的wx_id orderId 时间 total_fee
//      _, err = o.Insert(&models.WxBill{WxId:uid, OrderId:orderid_str, OutTradeNo:yourReq.Out_trade_no, TotalFee:strconv.Itoa(yourReq.Total_fee), CreateTime:time.Now().Format(TIMELAYOUT)})
//      if err != nil {
//          fmt.Println("记录wx_bill错误", err)
//          logUtils.GetLog().Error("记录wx_bill错误", err)
//      }
//
//      c.Data["prepay_id"] = xmlResp.Prepay_id
//      c.Data["appId"] = yourReq.Appid
//      c.Data["timeStamp"] = yourReq.Out_trade_no
//      c.Data["nonceStr"] = yourReq.Nonce_str
//      c.Data["signature"] = getTicketSigNature(o, c.Ctx.Input.URI(), &yourReq)
//
//      paySign := getPaySign(&yourReq, &xmlResp)
//      c.Data["paySign"] = paySign
//
//  } else {
//      fmt.Println("查询订单错误", err, order)
//      logUtils.GetLog().Error("查询订单错误", err, order)
//      return
//  }
//}

//获取支付签名 跟下单签名不同的地方在于 最后一个字符串连接没有&
func getPaySign(yourReq *UnifyOrderReq, xmlResp *UnifyOrderResp,timeStamp int64) string {

    wxbase := models.WxBase{Id:1}
    err := orm.NewOrm().Read(&wxbase)
    if err != nil {
        fmt.Println("获取wxbase错误", err)
        logUtils.GetLog().Error("获取wxbase错误", err)
        return ""
    }

    p := make(map[string]interface{}, 0)
    p["appId"] = yourReq.Appid
    //p["timeStamp"] = yourReq.Out_trade_no
    p["timeStamp"] = timeStamp
    p["nonceStr"] = yourReq.Nonce_str
    p["package"] = "prepay_id=" + xmlResp.Prepay_id
    p["signType"] = "MD5"

    return wxpaySign(p, wxbase.PayApiKey)
}

//计算支付签名 跟下单签名不同的地方在于 最后一个字符串连接没有&
func wxpaySign(mReq map[string]interface{}, key string) 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 i, k := range sorted_keys {
        //fmt.Printf("k=%v, v=%v\n", k, mReq[k])
        value := fmt.Sprintf("%v", mReq[k])
        if value != "" {
            if i != (len(sorted_keys) - 1) {
                signStrings = signStrings + k + "=" + value + "&"
            } else {
                signStrings = signStrings + k + "=" + value//最后一个不加此符号
            }
        }
    }
    //fmt.Println("=====键值对==============", signStrings)

    //STEP3, 在键值对的最后加上key=API_KEY
    if key != "" {
        signStrings = signStrings + "&key=" + key
    }
    fmt.Println("=====wxpaySign 键值对加key==============", signStrings)

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

    md5Ctx := md5.New()
    md5Ctx.Write([]byte(signStrings))
    cipherStr := md5Ctx.Sum(nil)
    upperSign := strings.ToUpper(hex.EncodeToString(cipherStr))

    fmt.Println("=====进行MD5签名并且将所有字符转为大写 ==============", upperSign)
    return upperSign
}

func getTicketSigNature(o orm.Ormer, uri string, yourReq *UnifyOrderReq) string {

    jsTicket := models.WxJsTicket{Id:1}
    if err := o.Read(&jsTicket, "id"); err == nil {

        //urlstr := beego.AppConfig.String("baseURL") + uri
        urlstr := `http://www.rollingbear.cn` + uri

        n := make(map[string]interface{}, 0)
        n["noncestr"] = yourReq.Nonce_str
        n["jsapi_ticket"] = jsTicket.Ticket
        n["timestamp"] = yourReq.Out_trade_no
        n["url"] = urlstr
        signature := wxJsTicketSign(n)
        fmt.Println("微信支付页面签名-----URI------", urlstr)
        fmt.Println("微信支付页面签名-----jsapi_ticket------", jsTicket.Ticket)
        fmt.Println("微信支付页面签名-----随机字符串------", yourReq.Nonce_str)
        fmt.Println("微信支付页面签名-----时间戳------", yourReq.Out_trade_no)
        fmt.Println("微信支付页面签名-----------", signature)
        return signature
    } else {
        fmt.Println("查询  jsticket 错误", err)
        logUtils.GetLog().Error("查询  jsticket 错误", err)
        return ""
    }
}

//微信支付页面config签名
func wxJsTicketSign(mReq map[string]interface{}) string {

    //fmt.Println("========STEP 1, 对key进行升序排序.========")
    //fmt.Println("微信支付签名计算, API KEY:", key)
    //STEP 1, 对key进行升序排序.
    sorted_keys := make([]string, 0)
    for k, _ := range mReq {
        sorted_keys = append(sorted_keys, k)
    }

    sort.Strings(sorted_keys)

    //fmt.Println("========STEP2, 对key=value的键值对用&连接起来,略过空值========")
    //STEP2, 对key=value的键值对用&连接起来,略过空值
    var signStrings string
    for i, k := range sorted_keys {
        //fmt.Printf("k=%v, v=%v\n", k, mReq[k])
        value := fmt.Sprintf("%v", mReq[k])
        if value != "" {
            if i != (len(sorted_keys) - 1) {
                signStrings = signStrings + k + "=" + value + "&"
            } else {
                signStrings = signStrings + k + "=" + value//最后一个不加此符号
            }
        }
    }

    //对字符串进行SHA1哈希
    t := sha1.New();
    io.WriteString(t, signStrings);
    upperSign := fmt.Sprintf("%x", t.Sum(nil));

    return upperSign
}

你看,这里的代码长的丧心病狂,实际上,连着注释掉的部分一起看,就是整个支付的逻辑,而上线的时候你不能还有test啊,否则不在白名单无法使用,那就得把test中的部分逻辑放到正式的WXShopCartPayController中去

WXShopCartPayController

package controllers

import (
    "github.com/astaxie/beego"
    "fmt"
    "io/ioutil"
    "strings"
    "net/http"
    "bytes"
    "github.com/astaxie/beego/orm"
    "strconv"
    "rbearserver/shopUtils/RandomStrUtil"
    "time"
    "rbearserver/models"
    "encoding/xml"
    "rbearserver/shopUtils/logUtils"
)


/**
     接收微信支付订单结果
 */


type WXShopCartPayController struct {
    beego.Controller
}

func (c *WXShopCartPayController) Get() {

    //if WXShopCartPayController_uid = GetWxIdInWxShop.GetWxId(c.Ctx, c.Ctx.Input.URI()); WXGoodInfoController_uid != "" {
    if wxid, _ := c.GetSession("uid").(string); wxid != "" {
        fmt.Println("WXShopCartPayController wxopenid = ", wxid)
        cgetShopCartForm(c, wxid)
    } else {
        fmt.Println("WXShopCartPayController uid==空")
    }
    c.TplName = "wx_shop_cart_pay_test.html"
}

func (c *WXShopCartPayController) Post() {

    c.EnableRender = false
    fmt.Println("WXShopCartPayController 接收微信支付订单结果--------------post")
    //微信支付回调函数 成功后跳转至订单页面
    WxpayCallback(c.Ctx.ResponseWriter.ResponseWriter, c.Ctx.Request)
}

func cgetShopCartForm(c *WXShopCartPayController, wxid string) {

    fmt.Println("走的是正式支付接口-----------2")
    orderid_str := c.GetString("orderid")
    orderid, _ := strconv.Atoi(orderid_str)//订单id 根据此id可以查询good_order表获取商品及购买者信息
    o := orm.NewOrm()
    order := models.GoodOrder{Id:orderid}

    if err := o.Read(&order, "id"); err == nil {

        orderPrice, _ := strconv.ParseFloat(order.OrderValue, 64)
        totalFee := int(orderPrice * 100)

        //请求UnifiedOrder的代码
        var yourReq UnifyOrderReq

        wxbase := models.WxBase{Id:1}
        err := orm.NewOrm().Read(&wxbase)
        if err == nil {
            yourReq.Appid = wxbase.AppID
            yourReq.Mch_id = wxbase.ShopKey//账户中心---商户信息---微信支付商户号
        } else {
            fmt.Println("获取wxbase错误", err)
            logUtils.GetLog().Error("获取wxbase错误", err)
            return
        }

        //yourReq.Appid = beego.AppConfig.String("APPID")
        yourReq.Body = "rbshop-" + order.Goodname//浏览器打开的移动网页的主页title名-商品概述
        //yourReq.Mch_id = beego.AppConfig.String("shopKey")
        yourReq.Nonce_str = RandomStrUtil.GetRandomString(32)
        yourReq.Notify_url = beego.AppConfig.String("baseURL") + "/shop_cart/pay"
        yourReq.Trade_type = "JSAPI"
        yourReq.Spbill_create_ip = c.Ctx.Input.IP()
        yourReq.Total_fee = totalFee // 单位是分 单位换为真实大小 注意要把元转换为分
        yourReq.Openid = wxid
        yourReq.Out_trade_no = strconv.FormatInt(time.Now().Unix(), 10) + RandomStrUtil.GetRandomString(3)//订单号

        var m map[string]interface{}
        m = make(map[string]interface{}, 0)
        m["appid"] = yourReq.Appid
        m["body"] = yourReq.Body
        m["mch_id"] = yourReq.Mch_id
        m["notify_url"] = yourReq.Notify_url
        m["trade_type"] = yourReq.Trade_type
        m["spbill_create_ip"] = yourReq.Spbill_create_ip
        m["total_fee"] = yourReq.Total_fee
        m["out_trade_no"] = yourReq.Out_trade_no
        m["nonce_str"] = yourReq.Nonce_str
        m["openid"] = yourReq.Openid
        yourReq.Sign = wxpayCalcSign(m, wxbase.PayApiKey) //这个key 微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全

        bytes_req, err := xml.Marshal(yourReq)
        if err != nil {
            fmt.Println("转换为xml错误:", err)
            logUtils.GetLog().Error("转换为xml错误:", err)
        }

        str_req := strings.Replace(string(bytes_req), "UnifyOrderReq", "xml", -1)
        //fmt.Println("转换为xml--------", str_req)

        bytes_req = []byte(str_req)

        //发送unified order请求.
        req, err := http.NewRequest("POST", "https://api.mch.weixin.qq.com/pay/unifiedorder", bytes.NewReader(bytes_req))
        if err != nil {
            fmt.Println("New Http Request发生错误,原因:", err)
            logUtils.GetLog().Error("New Http Request发生错误,原因:", err)
            return

        }
        req.Header.Set("Accept", "application/xml")
        //这里的http header的设置是必须设置的.
        req.Header.Set("Content-Type", "application/xml;charset=utf-8")

        client := http.Client{}
        resp, _err := client.Do(req)
        if _err != nil {
            fmt.Println("请求微信支付统一下单接口发送错误, 原因:", _err)
            logUtils.GetLog().Error("请求微信支付统一下单接口发送错误, 原因:", _err)
            return
        }

        //------------------到这里统一下单接口就已经执行完成了-------------------

        respBytes, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            fmt.Println("解析返回body错误", err)
            logUtils.GetLog().Error("解析返回body错误", err)
            return
        }
        xmlResp := UnifyOrderResp{}
        _err = xml.Unmarshal(respBytes, &xmlResp)
        //处理return code.
        if xmlResp.Return_code == "FAIL" {
            fmt.Println("微信支付统一下单不成功,原因:", xmlResp.Return_msg, " str_req-->", str_req)
            return
        }

        //这里已经得到微信支付的prepay id,需要返给客户端页面,由客户端继续完成支付流程

        //向数据库存入 WxBill 订单号yourReq.Out_trade_no user的wx_id orderId 时间 total_fee
        _, err = o.Insert(&models.WxBill{WxId:wxid, OrderId:orderid_str, OutTradeNo:yourReq.Out_trade_no, TotalFee:strconv.Itoa(yourReq.Total_fee), CreateTime:time.Now().Format(TIMELAYOUT)})
        if err != nil {
            fmt.Println("记录wx_bill错误", err)
            logUtils.GetLog().Error("记录wx_bill错误", err)
        }

        timeStamp := time.Now().Unix()
        c.Data["prepay_id"] = xmlResp.Prepay_id
        c.Data["appId"] = yourReq.Appid
        c.Data["timeStamp"] = timeStamp
        c.Data["configtimeStamp"] = yourReq.Out_trade_no
        c.Data["nonceStr"] = yourReq.Nonce_str
        fmt.Println("走的是正式支付接口----uri----", c.Ctx.Input.URI())
        c.Data["signature"] = getTicketSigNature(o, c.Ctx.Input.URI(), &yourReq)

        paySign := getPaySign(&yourReq, &xmlResp, timeStamp)
        c.Data["paySign"] = paySign

    } else {
        fmt.Println("查询订单错误", err, order)
        logUtils.GetLog().Error("查询订单错误", err, order)
        return
    }
}

OK,你看完就发现跟上面那个test其实没啥区别。为啥我不抽方法呢?因为我一想起来支付的过程就想吐,实在没有改一个字的欲望。

接下来,就是恶心的支付页面

我是非常非常非常非常讨厌写js的,要不是老板不舍得招人,迫不得已我才不写这玩意。

wx_shop_cart_pay_test.html

<!DOCTYPE html>
<html lang="en">
<head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <meta name="viewport" content="user-scalable=no">

    <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

    <title>商城</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <meta name="viewport" content="user-scalable=no">

    <link rel="stylesheet" type="text/css" href="../../static/css/bootstrap.min.css">
    <script src="../../static/js/jquery-3.0.0.min.js"></script>
    <script src="../../static/js/bootstrap.min.js"></script>

</head>
<body>

    <div class="container" style="margin-top: 60px">

        <input hidden type="text" id="prepay_id" value={{.prepay_id}}>
        <input hidden type="text" id="appId" value={{.appId}}>
        <input hidden type="text" id="configtimeStamp" value={{.configtimeStamp}}>
        <input hidden type="text" id="timeStamp" value={{.timeStamp}}>
        <input hidden type="text" id="nonceStr" value={{.nonceStr}}>
        <input hidden type="text" id="paySign" value={{.paySign}}>
        <input hidden type="text" id="signature" value={{.signature}}>


        <div class="center-block" style="width: 70%;margin-top: 10%">
            <h1 class="text-center" style="font-size: 4rem;color: #2CB618"> 微信交易请求申请 </h1>
            <img class="center-block" src="../../static/images/wx-tishi.png"
                 style="margin-top: 60px;height: 300px;width: 300px"/>
            <h1 class="text-center" style="font-size: 3.5rem;margin-top: 30px">正在提起微信订单</h1>
            <h1 class="text-center" style="font-size: 3rem;color:#7d7d7d;margin-top: 20px">请勿关闭该页面</h1>
        </div>

    </div>


    <script>

        var prepay_id = document.getElementById("prepay_id").value;
        var configtimeStamp = document.getElementById("configtimeStamp").value;
        var timeStamp = document.getElementById("timeStamp").value;
        var nonceStr = document.getElementById("nonceStr").value;
        var paySign = document.getElementById("paySign").value;
        var signature = document.getElementById("signature").value;

        var appId = document.getElementById("appId").value;

        wx.config({
            debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: appId, // 必填,公众号的唯一标识
            timestamp: configtimeStamp, // 必填,生成签名的时间戳
            nonceStr: nonceStr, // 必填,生成签名的随机串
            signature: signature,// 必填,签名
            jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
        });

        wx.ready(function () {
            // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

            wx.chooseWXPay({
                timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
                nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
                package: "prepay_id=" + prepay_id, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
                signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
                paySign: paySign, // 支付签名
                success: function (res) {
                    // 支付成功后的回调函数
                    alert("支付成功" + JSON.stringify(res));
                    location.href = "http://www.rollingbear.cn/wx_shop_cart/cart?showAll=1";
                },
                fail: function (res) {
                    console.log("支付失败-----" + res);
                    alert("支付失败" + JSON.stringify(res));
                },
                cancel: function (res) {
                    alert("用户取消支付");
                    location.href = "http://www.rollingbear.cn/wx_shop_cart/cart";
                }
            });

//            WeixinJSBridge.invoke('getBrandWCPayRequest', {
//                "appId": appId,     //公众号名称,由商户传入
//                "timeStamp": timeStamp,         //时间戳,自1970年以来的秒数
//                "nonceStr": nonceStr, //随机串
//                "package": "prepay_id=" + prepay_id,
//                "signType": "MD5",         //微信签名方式
//                "paySign": paySign //微信签名
//            }, function (res) {
//                if (res.err_msg == "get_brand_wcpay_request:ok") {
//                    alert("微信支付成功!");
//                } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
//                    alert("用户取消支付!");
//                } else {
//                    alert(JSON.stringify(res));
//                }
//                // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
//                //因此微信团队建议,当收到ok返回时,向商户后台询问是否收到交易成功的通知,若收到通知,前端展示交易成功的界面;若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
//            });


//            function onBridgeReady() {
//
//                WeixinJSBridge.invoke(
//                        'getBrandWCPayRequest', {
////                            "appId": appId,     //公众号名称,由商户传入
////                            "timeStamp": timeStamp,         //时间戳,自1970年以来的秒数
////                            "nonceStr": nonceStr, //随机串
////                            "package": "prepay_id=" + prepay_id,
////                            "signType": "MD5",         //微信签名方式
////                            "paySign": paySign //微信签名
//                        },
//                        function (res) {
//                            console.log("res.err_msg-----" + res.err_msg);
//                            // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
//                            if (res.err_msg == "get_brand_wcpay_request:ok") {
//                                console.log("res.err_msg--okokok---");
//                            }
//                        }
//                );
//            }
//
//            if (typeof WeixinJSBridge == "undefined") {
//                console.log("res.err_msg-----1");
//                if (document.addEventListener) {
//                    console.log("res.err_msg-----2");
//                    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
//                } else if (document.attachEvent) {
//                    console.log("res.err_msg-----3");
//                    document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
//                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
//                }
//            } else {
//                console.log("res.err_msg-----4");
//                onBridgeReady();
//            }
//
        });

        wx.error(function (res) {
            // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
            alert("wx config失败" + JSON.stringify(res));
        });


    </script>
</body>
</html>

如你所见,我使用了非常low的法子来获取传递过来的参数,先加载到页面的input上,然后再用js从input里获取传递过来的数据。而微信的处理代码被注释掉这么多,是因为我从文档里就找到这么多的奇葩代码,请容我再骂一句,这GRD文档,是哪个混球写的,不积德啊。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:u012210379

查看原文:使用golang快速开发微信公众平台(五):公众号支付

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

5775 次点击  
加入收藏 微博
1 回复  |  直到 2019-07-23 15:50:41
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传