01_微信小程序支付



【支付流程】

1.小程序內調用登錄接口,獲取到用戶的openid(我們這一步驟讓前端去獲取)

2.服務端代碼這邊生成訂單

3.服務端調用支付統一下單的api

4.服務端將再次簽名,返回5個參數(前端得到數據后可以調起支付)

5.微信后台會回調我們服務端,我們通過回調更新訂單狀態

6.前端也會調用服務端訂單查詢接口,服務端查詢訂單狀態(防止微信回調這邊的一個時間差),如果成功了,在這個接口里會向用戶發送一個小程序的模板消息(會消耗一個第3步的prepay_id,后續寫模板消息的時候會說)

[ 概述 ]

重點是步驟3和4,特別是簽名那塊的格式要求務必按照微信的要求來。

 

【流程詳解】

【 1.統一下單 】

目的:在小程序中先調用該接口在微信支付服務后台生成預支付交易單,返回正確的預支付交易后調起支付。

接口:

https://api.mch.weixin.qq.com/pay/unifiedorder

 請求參數

字段名 變量名 必填 類型 示例值 描述
小程序ID appid String(32) wxd678efh567hg6787 微信分配的小程序ID
商戶號 mch_id String(32) 1230000109 微信支付分配的商戶號
設備號 device_info String(32) 013467007045764 自定義參數,可以為終端設備號(門店號或收銀設備ID),PC網頁或公眾號內支付可以傳"WEB"
隨機字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 隨機字符串,長度要求在32位以內。推薦隨機數生成算法
簽名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 通過簽名算法計算得出的簽名值,詳見簽名生成算法
簽名類型 sign_type String(32) MD5 簽名類型,默認為MD5,支持HMAC-SHA256和MD5。
商品描述 body String(128) 騰訊充值中心-QQ會員充值

商品簡單描述,該字段請按照規范傳遞,具體請見參數規定

商品詳情 detail String(6000)   商品詳細描述,對於使用單品優惠的商戶,改字段必須按照規范上傳,詳見“單品優惠參數說明”
附加數據 attach String(127) 深圳分店 附加數據,在查詢API和支付通知中原樣返回,可作為自定義參數使用。
商戶訂單號 out_trade_no String(32) 20150806125346 商戶系統內部訂單號,要求32個字符內,只能是數字、大小寫字母_-|*@ ,且在同一個商戶號下唯一。詳見商戶訂單號
標價幣種 fee_type String(16) CNY 符合ISO 4217標准的三位字母代碼,默認人民幣:CNY,詳細列表請參見貨幣類型
標價金額 total_fee Int 88 訂單總金額,單位為分,詳見支付金額
終端IP spbill_create_ip String(16) 123.12.12.123 APP和網頁支付提交用戶端ip,Native支付填調用微信支付API的機器IP。
交易起始時間 time_start String(14) 20091225091010 訂單生成時間,格式為yyyyMMddHHmmss,如2009年12月25日9點10分10秒表示為20091225091010。其他詳見時間規則
交易結束時間 time_expire String(14) 20091227091010

訂單失效時間,格式為yyyyMMddHHmmss,如2009年12月27日9點10分10秒表示為20091227091010。訂單失效時間是針對訂單號而言的,由於在請求支付的時候有一個必傳參數prepay_id只有兩小時的有效期,所以在重入時間超過2小時的時候需要重新請求下單接口獲取新的prepay_id。其他詳見時間規則

建議:最短失效時間間隔大於1分鍾

訂單優惠標記 goods_tag String(32) WXG 訂單優惠標記,使用代金券或立減優惠功能時需要的參數,說明詳見代金券或立減優惠
通知地址 notify_url String(256) http://www.weixin.qq.com/wxpay/pay.php 異步接收微信支付結果通知的回調地址,通知url必須為外網可訪問的url,不能攜帶參數。
交易類型 trade_type String(16) JSAPI 小程序取值如下:JSAPI,詳細說明見參數規定
商品ID product_id String(32) 12235413214070356458058 trade_type=NATIVE時(即掃碼支付),此參數必傳。此參數為二維碼中包含的商品ID,商戶自行定義。
指定支付方式 limit_pay String(32) no_credit 上傳此參數no_credit--可限制用戶不能使用信用卡支付
用戶標識 openid String(128) oUpF8uMuAJO_M2pxb1Q9zNjWeS6o trade_type=JSAPI,此參數必傳,用戶在商戶appid下的唯一標識。openid如何獲取,可參考【獲取openid】。

 [ 統一下單的注意點 ]

1.簽名sign生成算法,詳見https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3

2.隨機字符串nonce_str,可以用加入當前時間戳+隨機數的方法來生成

3.交易類型trade_type,小程序是JSAPI

4.統一下單和接下來的再次簽名的簽名類型sign_type,都統一使用MD5加密,不然可能會出現驗證簽名失敗的情況,注意這是一個大坑。

[簡易代碼示例] 

//第1步:拼接對應的參數
Map<String, String> param = new TreeMap<>();
param.put("appid", Config.MINI_PROGRAM_APP_ID);  //像這些值,最好有個微信config類來存
param.put("mch_id", Config.MCH_ID);
param.put("openid", openId);
param.put("attach", orderDesc);
param.put("body", orderDesc);
param.put("detail", orderDesc);
param.put("limit_pay", Config.NO_CREDIT_LIMIT_PAY);
param.put("nonce_str", nonceStr);
param.put("notify_url", Config.UNIFIED_ORDER_NOTIFY_RELATIVE_URL);
param.put("out_trade_no", outTradeNo);
param.put("spbill_create_ip", clientIp);
param.put("total_fee", String.valueOf(totalFee));
param.put("trade_type", tradeType);
param.put("sign_type","MD5");
//第2步:生成簽名
StringBuilder urlParam = new StringBuilder();
for (String paramKey : param.keySet()) {   //排序
    urlParam.append(paramKey).append("=").append(param.get(paramKey)).append("&");
}
String preParam = urlParam.toString().substring(0, urlParam.toString().length() - 1);  //拼接的urlParam最后有一個&,刪除
String finalParam = preParam + "&key=" + WeiXinConfig.PRIVATE_KEY;   //key不參與排序
String sign = MD5.sign(finalParam, Const.Charset.UTF8).toUpperCase();  //排序后的參數+key 進行MD5簽名,並且全部大寫

//第三步:方便后續生成xml格式請求體,簡易用一個類來封裝對應的參數,然后返回
request.setAppId(param.get("appid"));
request.setSign(sign);
//request.set...其他參數,但要額外加一個成員變量存儲sign

 

[ 返回結果 ]

字段名 變量名 必填 類型 示例值 描述
返回狀態碼 return_code String(16) SUCCESS

SUCCESS/FAIL

此字段是通信標識,非交易標識,交易是否成功需要查看result_code來判斷

返回信息 return_msg String(128) 簽名失敗

返回信息,如非空,為錯誤原因

簽名失敗

參數格式校驗錯誤

以下字段在return_code為SUCCESS的時候有返回

字段名 變量名 必填 類型 示例值 描述
小程序ID appid String(32) wx8888888888888888 調用接口提交的小程序ID
商戶號 mch_id String(32) 1900000109 調用接口提交的商戶號
設備號 device_info String(32) 013467007045764 自定義參數,可以為請求支付的終端設備號等
隨機字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 微信返回的隨機字符串
簽名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 微信返回的簽名值,詳見簽名算法
業務結果 result_code String(16) SUCCESS SUCCESS/FAIL
錯誤代碼 err_code String(32) SYSTEMERROR 詳細參見下文錯誤列表
錯誤代碼描述 err_code_des String(128) 系統錯誤 錯誤信息描述

以下字段在return_code 和result_code都為SUCCESS的時候有返回

字段名 變量名 必填 類型 示例值 描述
交易類型 trade_type String(16) JSAPI 交易類型,取值為:JSAPI,NATIVE,APP等,說明詳見參數規定
預支付交易會話標識 prepay_id String(64) wx201410272009395522657a690389285100 微信生成的預支付會話標識,用於后續接口調用中使用,該值有效期為2小時
二維碼鏈接 code_url String(64) URl:weixin://wxpay/s/An4baqw trade_type為NATIVE時有返回,用於生成二維碼,展示給用戶進行掃碼支付

 

 【2.再次簽名】

統一下單后,需要再次簽名后,才能將數據返回給前端,不然會出現前端能調起微信支付,但是在支付過程中一直報簽名失敗的提示。

再次簽名無需請求微信后台,只是自己對統一下單的一些參數做一次生成簽名而已。

[ 再起簽名需要的參數 ]

字段名 變量名 必填 類型 示例值 描述
小程序ID appId String wxd678efh567hg6787 微信分配的小程序ID
時間戳 timeStamp String 1490840662 時間戳從1970年1月1日00:00:00至今的秒數,即當前的時間
隨機串 nonceStr String 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 隨機字符串,不長於32位。推薦隨機數生成算法
數據包 package String prepay_id=wx2017033010242291fcfe0db70013231072 統一下單接口返回的 prepay_id 參數值,提交格式如:prepay_id=wx2017033010242291fcfe0db70013231072
簽名方式 signType String MD5 簽名類型,默認為MD5,支持HMAC-SHA256和MD5。注意此處需與統一下單的簽名類型一致

舉例如下:(必須和這里的格式一致,紅色部分的也一樣!)

paySign = MD5(appId=wxd678efh567hg6787&nonceStr=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=wx2017033010242291fcfe0db70013231072&signType=MD5&timeStamp=1490840662&key=qazwsxedcrfvtgbyhnujmikolp111111)

[ 簡易代碼示例 ]

//第1步:拼接對應的參數
Map<String, String> param = new TreeMap<>();
String nonceStr = WeiXinPayUtils.generateNonceStr();  //專門寫了個方法來生成隨機字符串
param.put("appId", Config.MINI_PROGRAM_APP_ID);
param.put("package", "prepay_id="+prepayId);   //從統一下單響應的結果中取的參數
param.put("nonceStr", nonceStr);
param.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));  //秒級別的時間戳,應該毫秒也OK
param.put("signType","MD5");   //小程序,這里和統一下單的簽名類型保持一致
//第2步:再次生成簽名
StringBuilder urlParam = new StringBuilder();
for (String paramKey : param.keySet()) {
    urlParam.append(paramKey).append("=").append(param.get(paramKey)).append("&");
}
String preParam = urlParam.toString().substring(0, urlParam.toString().length() - 1);
String finalParam = preParam + "&key=" + Config.PRIVATE_KEY;
String sign = MD5.sign(finalParam, Const.Charset.UTF8).toUpperCase();
//同理,這里建議做一個響應參數給前端
需要返回給前端的參數有:
response.setSign(sign);
response.setAppId(param.get("appId"));
response.setPrepayId(weiXinUnifiedOrderResponse.getPrepayId);  //統一下單的響應數據
response.setNonceStr(param.get("nonceStr"));
response.setTimeStamp(param.get("timeStamp"));
response.setPayWay(Const.PayWay.WEIXIN);
response.setAmount(amount);
response.setSignType("MD5");
response.setOrderNo(outTradeNo);
response.setCodeUrl(weiXinUnifiedOrderResponse.getCodeUrl());//統一下單的響應數據

再次簽名之后,前端就可以根據服務端返回的參數發起正常的微信支付了。

【3.前端調微信支付需要的參數(即服務端響應參數必傳參數)】 

參考文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3

前端調用wx.requestPayment(OBJECT)發起微信支付

注意:里面的時間戳timeStamp,nonceStr,package,signType,paySign都是服務端的參數,不是前端自己生成的隨機數,注意!!!

要理解微信那邊也只是根據這些數據來生成簽名,會與我們再次簽名生成的簽名(即paySign)做一次比較,而這個paySign就是由這幾個參數加密生成的,自己做項目時沒有清楚意識到這一點,時間戳傳給前端有誤導致一直簽名失敗,這里是個坑,要注意。

Object參數說明:

參數 類型 必填 說明
timeStamp String 時間戳從1970年1月1日00:00:00至今的秒數,即當前的時間
nonceStr String 隨機字符串,長度為32個字符以下。
package String 統一下單接口返回的 prepay_id 參數值,提交格式如:prepay_id=*
signType String 簽名類型,默認為MD5,支持HMAC-SHA256和MD5。注意此處需與統一下單的簽名類型一致
paySign String 簽名,具體簽名方案參見微信公眾號支付幫助文檔;
success Function 接口調用成功的回調函數
fail Function 接口調用失敗的回調函數
complete Function 接口調用結束的回調函數(調用成功、失敗都會執行)

 

回調結果:

回調類型 errMsg 說明
success requestPayment:ok 調用支付成功
fail requestPayment:fail cancel 用戶取消支付
fail requestPayment:fail (detail message) 調用支付失敗,其中 detail message 為后台返回的詳細失敗原因

示例代碼(前端代碼):

wx.requestPayment(
{
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){
},
'fail':function(res){},
'complete':function(res){
}
})

 

【微信小程序官方參考】

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM