01_微信小程序支付
【支付流程】
1.小程序內調用登錄接口,獲取到用戶的openid(我們這一步驟讓前端去獲取)
2.服務端代碼這邊生成訂單
3.服務端調用支付統一下單的api
4.服務端將再次簽名,返回5個參數(前端得到數據後可以調起支付)
5.微信後臺會回調我們服務端,我們通過回調更新訂單狀態
6.前端也會調用服務端訂單查詢接口,服務端查詢訂單狀態(防止微信回調這邊的一個時間差),如果成功了,在這個接口裏會向用戶發送一個小程序的模板消息(會消耗一個第3步的prepay_id,後續寫模板消息的時候會說)
[ 概述 ]
重點是步驟3和4,特別是簽名那塊的格式要求務必按照微信的要求來。
【流程詳解】
【 統一下單 】
目的:在小程序中先調用該接口在微信支付服務後臺生成預支付交易單,返回正確的預支付交易後調起支付。
接口:
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時有返回,用於生成二維碼,展示給用戶進行掃碼支付 |
【微信小程序官方參考】
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3
01_微信小程序支付