微信支付JSAPI,實測!終極方案

在用JSAPI開發微信支付的時候,遇到了很多坑,我也對朋友說過,一步一坑。最後終於算是走出來了。期間翻閱過很多網友寫的教程,但是都不實用,JAVA,Python都有看過,大多數都是粘貼複製,倍感失望。

開發環境

thinkphp5.0 php

(開始使用JSAPI需要一個概念,就是在整個JSAPI的邏輯裏面,只存在一個隨機字符串 和一個 時間戳。相當於JSSAPI類裏的全局。)

開始開發

全局初始化

 public function __construct($total_fee, $body, $openid)
    {
        $rand = rand(11, 99);
        $mp_info = get_mpid_info();//獲取微信信息
        $this->appid = $mp_info['appid'];
        $this->nonce_str = nonceStr(32);
        $this->spbill_create_ip = Request::instance()->ip();
        $this->mch_id = $mp_info['mch_id'];
        $this->key = $mp_info['paykey'];
        $this->timestamp = time();
        $this->sign;//一次簽名
        $this->total_fee = $total_fee;
        $this->out_trade_no = time() . $rand;
        $this->notify_url = 'http://uedream.cn/index.php';
        $this->body = $body;
        $this->openid = $openid;
        $this->sign_type = 'MD5';
        $this->createsign(); //生成簽名方法,需要結合createsign方法
    }

以上是初始化簽名結構體

獲取簽名

文檔:https://pay.weixin.qq.com/wik...
public function createsign()
    {
        $build = [
            'appid' => $this->appid,
            'body' => $this->body,
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->nonce_str,
            'notify_url' => $this->notify_url,
            'openid' => $this->openid,
            'out_trade_no' => $this->out_trade_no,
            'sign_type' => $this->sign_type,
            'spbill_create_ip' => $this->spbill_create_ip,
            'timeStamp' => $this->timestamp,
            'total_fee' => $this->total_fee,
            'trade_type' => $this->trade_type,
            'key' => $this->key,
        ];
        $string = http_build_query($build);
        $string = str_replace('%2F', '/', $string); //格式化網址
        $string = str_replace('%3A', ':', $string); //格式化網址
        $md5 = md5($string);
        $this->sign = strtoupper($md5);
    }

統一下單

文檔:https://pay.weixin.qq.com/wik...
 public function unifiedorder()
    {

        $data = [
            'appid' => $this->appid,
            'body' => $this->body,
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->nonce_str,
            'notify_url' => $this->notify_url,
            'openid' => $this->openid,
            'out_trade_no' => $this->out_trade_no,
            'sign' => $this->sign,
            'sign_type' => 'MD5',
            'spbill_create_ip' => $this->spbill_create_ip,
            'timeStamp' => $this->timestamp,
            'total_fee' => $this->total_fee * 1,
            'trade_type' => $this->trade_type,
        ];
        $xml = arrayToXml($data);
        $result = http_post(self::UNIFIEDORDER, $xml);
        $return = xmlToArray($result);
        $this->package = 'prepay_id=' . $return['prepay_id'];
        $this->renCreatesign();//這是二次簽名。文檔裏面我是沒有看到,反正我是卡到這裏了。
        $returns = [
            'appid' => $this->appid,
            'noncestr' => $this->nonce_str,
            'signtype' => $this->sign_type,
            'package' => $this->package,
            'sign' => $this->resign,
            'timestamp' => $this->timestamp,
        ];
        return $returns;
    }

統一下單請忽略的所有的回調參數,只要prepay_id,其它的參數暫時看做障眼法,獲取到了統一下單,還需要進行二次簽名,上面代碼裏面有一個$this->renCreatesign(),就是調用的二次簽名方法

二次簽名

文檔:https://pay.weixin.qq.com/wik...

所謂的二次簽名就是,appId,nonceStr,package,signType,timeStamp,key的加密。一樣的簽名方式,可是參考簽名文檔,進行簽名。(上面參數已經按照ASCII進行排序,大小寫也請按照給出的進行加密)
注意: package格式爲prepay_id=xxxxxxxxxxxx。xxxx部分爲統一下單獲取的prepay_id

代碼參考:

public function renCreatesign()
    {
        $build_data = [
            'appId' => $this->appid,
            'nonceStr' => $this->nonce_str,
            'package' => $this->package,
            'signType' => $this->sign_type,
            'timeStamp' => $this->timestamp,
            'key' => $this->key,
        ];
        $result = http_build_query($build_data);
        $put_data = str_replace('%3D', '=', $result); //格式化網址
        $signatrue = md5($put_data);

        $this->resign = strtoupper($signatrue);

    }

至此,所有的簽名應經完成,控制器使用unifiedorder()進行參數獲取。

前端

這裏開始使用jsapi做支付動作

            WeixinJSBridge.invoke(
                "getBrandWCPayRequest",
                {
                  appId: res.appid, //公衆號名稱,由商戶傳入
                  timeStamp: res.timeStamp, //時間戳,自1970年以來的秒數
                  nonceStr: res.nonce_str, //隨機串
                  package: res.package,
                  signType: res.signType, //微信簽名方式:
                  paySign: res.sign //微信簽名
                },
                function(res) {
                  alert(JSON.stringify(res));
                  if (res.err_msg == "get_brand_wcpay_request:ok") {
                    // 使用以上方式判斷前端返回,微信團隊鄭重提示:
                    //res.err_msg將在用戶支付成功後返回ok,但並不保證它絕對可靠。
                  }
                }
              );

前端所有需要調用的參數均在unifiedorder()可以獲取到。

這裏提一下WeixinJSBridge.invokewx.chooseWXPay 的區別。WeixinJSBridge.invoke可以不用引用weixinjs便可使用,也不需要config。在安卓手機上也能回調出錯誤信息。wx.chooseWXPay需要引用weixinjs,也需要使用config,而且在安卓手機上面的提示特別不友好。

結語

微信支付文檔說實話真的很坑 很坑。貌似寫文檔的小哥這天情緒不好。寫出來的讓人也感覺到了情緒不好。以上爲本人切身操作寫出的教程。如還有補充的地方可以隨時留言評論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章