上一篇講到拿到了 預支付交易標識 wx251xxxxxxxxxxxxxxxxxxxxxxxxxxxxx078700
第四步,是時候微信內H5調起支付了!
先准備網頁端接口請求參數列表
微信文檔中已經明確給出了所有參數名和參與簽名計算的參數,即
- appId,具有支付權限的與微信支付商戶關聯綁定的公眾號的APPID
- timeStamp,10位當前Unix時間
- nonceStr,<=32 位的隨機信息,請求方自行隨意生成即可
- package,統一下單接口返回的prepay_id參數值,提交格式為:prepay_id=xxx
- signType,簽名方式,MD5或HMAC-SHA256,默認MD5,需要與統一下單的簽名類型一致
- paySign,計算后的簽名值
計算簽名
微信文檔中給出參與簽名的參數是 appId、timeStamp、nonceStr、package、signType,要注意計算簽名的方法和《微信支付 第二篇 JSAPI 調用統一下單接口獲取預支付交易數據》計算方式是一致的,回顧一下
- 先把參數正序排序
- 參數值為空的去除不參與下面計算
- 把所有符合條件的參數鍵值對按照URL查詢參數格式組成字符串即 key1=value1&key2=value2...得到結果字符串 StringA
- 把 StringA 后面再加上一個參數值對即 ...&key=MCHKEY 得到結果字符串 StringB (MCHKEY為商戶密鑰)
- 將 StringB 按簽名方式 signType 進行計算
- 將計算結果轉為大寫字符串,該值賦值給 paySign
需要注意的是,參數名要嚴格按照騰訊文檔的命名方式,包括大小寫,如 appId 不能寫成 appid 或 appID。開發時為了方便,H5頁面將部分參數設置成了可編輯文本框,先看一下它的樣子
本例中,點擊創建隨機字符串將獲得當前時間戳,將其作為 nonceStr 和 timeStamp 的值,點擊創建簽名計算出完整結果,本例中由於 JS 實現 hmacsha256 比較麻煩,就改用了 MD5 方式,根據微信要求統一下單接口中的簽名算法也改為了 MD5,下面列出本例實現代碼
<!--創建完整簽名-->
<script type="text/javascript">
function onCreatePaySign() {
// 從網頁的各個文本框獲取參數值
var appid = $("#text-appid").val();
var nonceStr = $("#text-nonceStr").val();
var prepayid = $("#text-prepayid").val();
var timeStamp = nonceStr;
var signType = "MD5";
// 拼接字符串
var sourceStr = "";
sourceStr += "appId=" + appid;
sourceStr += "&nonceStr=" + nonceStr;
sourceStr += "&package=prepay_id=" + prepayid;
sourceStr += "&signType=" + signType;
sourceStr += "&timeStamp=" + timeStamp;
sourceStr += "&key=asxxxxxxxxxxxxxxxN82";
// MD5方式計算
var hash = md5(sourceStr).toUpperCase();
// 在頁面中查看一下計算結果
$("#text-paySign").val(hash);
// 在控制台查看拼接字符串原文和MD5結果
console.log("拼接字符串結果: " + sourceStr);
console.log("MD5結果: " + hash);
}
</script>
對比查看結果(為了不泄露,appId和mchKey均作了處理,但因為算法固定,因此簽名計算結果完全不影響正確性)
真實設備下調用微信支付接口進行實際支付
這一步的"坑"是,必須要在真實設備下進行訪問,也就是手機、平板等運行微信APP的設備,微信開發者工具都不行,會報錯無法運行。因此,H5 頁面或者說運行微信支付的那部分 JS 一定要在真實設備上才能正確運行。先看一下微信給出的源代碼(官方文檔里有)
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入
"timeStamp":"1395712654", //時間戳,自1970年以來的秒數
"nonceStr":"e61463f8efa94090b1f366cccfbbb444", //隨機串
"package":"prepay_id=u802345jgfjsdfgsdg888",
"signType":"MD5", //微信簽名方式:
"paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ){
// 使用以上方式判斷前端返回,微信團隊鄭重提示:
//res.err_msg將在用戶支付成功后返回ok,但並不保證它絕對可靠。
}
});
}
就是這段代碼,必須要在真實設備運行,因此本例中采取的方式是將 H5 頁面放到服務器上,用開發者工具運行 獲取openid 和 獲取預支付交易標識 兩個步驟,拿到交易標識后在手機端微信里打開 H5 頁面,生成簽名並運行支付。根據實際情況,對放到 H5 頁面中的 onBridgeReady 函數進行了修改,使其從文本框中獲取真實數據
<!--微信支付調用-->
<script type="text/javascript">
function onBridgeReady() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": $("#text-appid").val(), //公眾號名稱,由商戶傳入
"timeStamp": $("#text-nonceStr").val(), //時間戳,自1970年以來的秒數
"nonceStr": $("#text-nonceStr").val(), //隨機串
"package": "prepay_id=" + $("#text-prepayid").val(),
"signType": "MD5", //微信簽名方式:
"paySign": $("#text-paySign").val() //微信簽名
},
function (res) {
console.log("微信支付返回值:");
console.log(res);
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判斷前端返回,微信團隊鄭重提示:
//res.err_msg將在用戶支付成功后返回ok,但並不保證它絕對可靠。
alert("get_brand_wcpay_request:ok");
}
alert(res.err_msg);
alert(res); // 顯示是個 Object
});
}
</script>
在手機中,點擊頁面上的支付按鈕,將調起真實的微信支付頁面,支付時忘了截圖,首先先顯示的是信息頁和金額,點擊支付輸入密碼/錄入指紋,驗證成功即支付成功,顯示支付成功頁面(這個有),並且在用戶微信內也會接到來自微信支付的通知消息。本例實現時並沒有做H5支付成功后的處理頁面,因此在支付成功頁面中點擊完成,就回到了H5頁面中,運行了 function (res) 內的代碼,並在彈窗中顯示出了相關信息
總結
至此,完成了微信支付 JSAPI 支付主要流程。羅列一下關鍵點
- 服務器環境使用了自有真實網站 wxpay.txxxt.com,完整路徑 http://wxpay.txxxt.com/jsapi/,這也是在商戶管理后台的 支付授權目錄 中配置的路徑,即發起微信支付調用的頁面是來自該目錄
- 所有頁面和接口都放在了該目錄下,getCode.php + codeCallback.php 配合獲取 openid,unifiedorder.php?openid=xxxx 負責根據openid獲取預支付交易標識,拿到交易標識后 h5pay.html 負責調起支付
- 前兩項可以在web開發者工具內運行,選擇公眾號網頁調試即可,調起支付必須在真實設備運行