本文裏說的微信公衆號支付對接指的是對接第三方支付平臺的微信公衆號支付接口。 非微信支付官方文檔裏的公衆號支付開發者文檔那樣的對接。不過,畢竟騰訊會把一部分渠道放給銀行或有支付牌照的支付機構,因此,第三方的公衆號支付也是在騰訊微信公衆號支付的基礎上作的改造。因此,基本的請求參數、簽名機制、響應參數、交互流程、數據格式都一致的。php
.....html
2.1 行業背景
微信支付,是基於微信客戶端提供的支付服務功能。同時向商戶提供銷售經營分析、帳戶和資金管理的功能支持。用戶經過掃描二維碼、反掃二維碼等多種方式調起微信支付模塊完成支付。
【二維碼支付正掃和反掃的區別在哪裏】
正掃:即收款碼支付,也就是商戶提供收款二維碼,而消費者用手機APP掃碼支付
反掃:即付款碼支付,也就是消費者提供付款二維碼,而商戶使用掃描槍掃碼收款
2.1.1公衆號支付
公衆號支付是用戶在微信中打開商戶的H5頁面,商戶在H5頁面經過調用微信支付提供的JSAPI接口調起微信支付模塊完成支付。應用場景有:
◆ 用戶在微信公衆帳號內進入商家公衆號,打開某個主頁面,完成支付
◆ 用戶的好友在朋友圈、聊天窗口等分享商家頁面鏈接,用戶點擊連接打開商家頁面,完成支付
◆ 將商戶頁面轉換成二維碼,用戶掃描二維碼後在微信瀏覽器中打開頁面後完成支付前端
【兩種實現方式】:原生態js支付和封裝形式算法
2.2 業務實現流程
2.2.1 公衆帳號支付業務json
微信內網頁支付時序圖swift
從圖可知,商戶系統涉及到的交互操做:api
1. 生成圖文消息連接或二維碼
4. 生成商戶訂單
5. 調用統一下單API------------------------
6. 生成JSAPI頁面調用的支付參數並簽名
10.異步通知商戶結果-----------------------
13.查詢後臺支付結果
14.調用查詢API,查詢支付結果--------------瀏覽器
xml安全
4.2簽名算法微信
MD5簽名
MD5是一種摘要生成算法,經過在簽名原始串後加上商戶通訊祕鑰,進行MD5運算,造成的摘要字符串即爲簽名結果。
4.2.1生成隨機數算法
微信支付API接口協議中包含字段nonce_str,主要保證簽名不可預測。咱們推薦生成隨機數算法以下:調用隨機數函數生成,將獲得的值轉換爲字符串。
通知重試機制
6.1 初始化請求接口
6.1.1 業務功能
初始化JSAPI 請求,經過生成token_id 來進行交互驗證。
字段名 | 變量名 | 必填 | 類型 | 說明 |
是否原生態 | is_raw | √ | string(1) | 是否原生態 |
用戶openid | sub_openid | - | string(128) | 微信用戶關注商家公衆號的openid(注: 使用測試商戶號不須要傳用戶openid; 切換正式的商戶號需獲取openid,並把獲取的openid 值傳給sub_openid。在切換成正式商戶號傳sub_openid 參數前,需提供正式商戶號和公衆號(服務號)appid 由渠道方配置,若是沒有配置的話,會報sub_appid and su_openid not match 錯誤,致使沒法正常調用接口)---------後文介紹如何獲取openid |
前臺地址 | callback_url | - | string(255) | 交易完成後跳轉的URL,需給絕對路徑,255 字符內格式 如:http://wap.tenpay.com/callback.asp 注:該地址只做爲前端頁面的一個跳轉,需使用notify_url 通知結果做爲支付最終結果。---------掃碼支付無此參數,即不須要商戶上送交易完成的h5頁面的。公衆號支付這個參數可選,商戶上送此頁面也可作一些營銷活動 |
是否限制信用卡 | limit_credit_pay |
- | String(32) | 限定用戶使用微信支付時可否使用信用卡,值爲1,禁用信用卡;值爲0 或者不傳此參數則不由用---------默認是支持信用卡的,因此此字段可不上送, 微信我的轉帳是不支持信用卡消費的,這正是與公衆號支付和掃碼支付最大的區別 |
6.1.2 交互模式
請求:後臺請求交互模式
返回結果+通知:後臺請求交互模式+後臺通知交互模式
注意:通常失敗的結果不簽名。
是否原生態is_raw 否String(1) 值爲1:是(對應文檔6.2 一節);
值爲0:否(對應文檔6.3 一節);不傳默認是0
6.2 原生態js 支付接口-----------------------原生態js支付實例:能夠關注「1號外賣」這個公衆號或者直接在手機微信裏錢包中的手機充值查看
6.3 公衆帳號JS 支付接口------------這是所謂的「封裝形式」(H5網頁支付模式)
6.3.1 業務功能
初始化JSAPI 請求,經過生成token_id 來進行交互驗證。
如調用時是用的原生態js 支付,此接口能夠忽略
6.4 JS 支付通知接口
同《威富通掃碼支付接口文檔V1.4.2.pdf》6.2 掃碼通知接口
——————【重要】首先必看.txt——————————————————————————————————————————
1.開發時能夠先使用測試商戶號和密鑰(demo中也都有寫)
測試
商戶號:'7551000001'
密鑰:'9d101c97133837e13dde2d32a5054abb'
2.測試商戶號有支付金額1元的限制,正式商戶號不會有
3.文檔中請求接口時傳的參數,必填爲是的參數是必需要傳的(若有缺乏會報錯),必填爲否的參數能夠傳也能夠不傳
4.返回參數中必填爲是的參數是必定會返回的,必填爲否的參數則不必定返回,必須以實際接收到的參數爲準
5.注意看文檔裏提供了兩種實現方式,PHP和C#版本demo中實現的是咱們封裝的形式,調用支付請求接口獲取到token_id,而後組裝成https://pay.swiftpass.cn/pay/jspay?token_id=9a0610bc519e782e6275e8c7dd94a445&showwxtitle=1這樣的連接在服務號中調起支付(用戶點擊頁面中的微信支付按鈕時實際上就是點擊的這個連接),JAVA版本則原生態js支付和封裝形式都有實現,原生態支付時是調用支付請求接口獲取到pay_info,取其中的參數去調用微信jsapi(這種方式最後調起微信時跟官方原生接口一致)
封裝形式只需點擊連接,簡單些,實例:能夠關注「廣州市站」這個公衆號具體看看
原生態js支付實例:能夠關注「1號外賣」這個公衆號或者直接在手機微信裏錢包中的手機充值查看
6.demo中用測試商戶號不須要傳用戶openid,即sub_openid參數置空
但切換正式的商戶號時調用接口請求參數必須給sub_openid參數傳入openid,同時請提供正式商戶號和公衆號(服務號)appid由我方配置,若是沒有配置的話,會報sub_appid and su_openid not match錯誤,致使沒法正常調用接口
獲取openid 指導文檔地址:http://www.cnblogs.com/txw1958/p/weixin76-user-info.html
獲取公衆號appid指導文檔地址:http://jingyan.baidu.com/article/6525d4b12af618ac7c2e9468.html
——————公衆號支付兩種實現模式的說明———————————————————————————————————————
公衆號支付流程是先調用接口文檔6.1一節初始化請求接口獲取到相應的返回值token_id和pay_info(對應的值是json 格式字符串,僅當is_raw=1時才返回),返回參數按 XML 的格式示例以下圖:
而後下一個步驟分爲了兩個不一樣的模式:6.2一節原生態js支付和6.3一節公衆帳號JS支付
6.2原生態js支付
調用微信jspai方法,此方法只能在微信內置瀏覽器調用,在其餘瀏覽器中無效,示例以下(注:示例代碼中appId這六個參數有大小寫,對應的值就是初始化請求接口中返回參數pay_info的值):
function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest',{ "appId" : "wx1f87d44db95cba7a", //公衆號名稱,由商戶傳入
"timeStamp": "1468591622013", //時間戳,自1970 年以來的秒數
"nonceStr" : "1468591622013", //隨機串
"package" : "prepay_id=wx201607152207013ae4e376760784153308", "signType" : "MD5", //微信簽名方式:
"paySign" : "AD5A9E19D38002461812E09C0910A815" //微信簽名,
},function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { // 此處可使用此方式判斷前端返回,微信團隊鄭重提示:res.err_msg 將在用戶支付成功後返回ok,但並不保證它絕對可靠,。
document.location.href="pay_success.jsp"; } /* for(var i in res){ alert(res[i]); } */ } ); }
最後在網頁代碼裏調用這個js方法就可調起微信支付好比:
<button type="button" onclick="jsApiCall()" >微信支付</button>
但想正常彈出支付密碼框,商戶方開發人員必須提供本身的支付受權目錄由服務商配置好,支付受權目錄即爲jspai方法代碼所在頁面的文件路徑,如http://xxxx.com/zhifu/jsapi.html,受權目錄就是http://xxxx.com/zhifu/(若是沒有配置受權目錄的話,支付時會沒法彈出密碼框或者提示當前頁面URL未註冊)
6.3公衆帳號JS支付
這種模式是由咱們進行了封裝,用6.1一節初始化請求接口獲取到的token_id值組裝成https://pay.swiftpass.cn/pay/jspay?token_id=1315838a57d0c83df0b62816220da070&showwxtitle=1這樣的連接在手機微信中調起支付(用戶點擊頁面中的微信支付按鈕時實際上就是點擊的這個連接,能夠將連接放在手機微信文件傳輸助手去點擊測試,注意token_id的值要更換有效的),這種模式不用實現jsapi方法,也不要提供支付受權目錄。
對比6.2一節原生態js支付,直接點擊連接的這個形式在支付彈出確認支付的彈出框時會多一個上面綠色下面白色背景頁面,實際上這個背景頁面是咱們封裝好的支付受權目錄頁面(對應固定的受權目錄https://pay.swiftpass.cn/pay/),這也是不用商戶提供支付受權目錄的緣由所在。
效果如圖:
總的來講,封裝的連接形式開發時簡單些,且無需商戶提供本身的受權目錄(由咱們固定配置https://pay.swiftpass.cn/pay/),但體驗可能沒有原生態js支付好。
參考:
微信支付開發文檔 https://pay.weixin.qq.com/wiki/doc/api/index.html
微信支付公衆號支付開發文檔 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
微信公衆號支付H5調用詳解(附代碼)http://blog.csdn.net/qq_28590639/article/details/49099275
——————獲取微信用戶的openid———————————————————————————————————————
關於用戶openid:在關注者與公衆號產生消息交互後,公衆號可得到關注者的OpenID(加密後的微信號,每一個用戶對每一個公衆號的OpenID是惟一的。對於不一樣公衆號,同一用戶的openid不一樣)。
獲取openid屬於微信公衆平臺開發的範疇,可參考如下地址:http://www.cnblogs.com/txw1958/p/weixin76-user-info.html 第三節《經過OAuth2.0方式不彈出受權頁面得到用戶基本信息》
step1:配置回調域名
登錄微信公衆平臺,菜單「設置」→「公衆號設置」→功能設置→網頁受權域名
用戶在網頁受權頁贊成受權給公衆號後,微信會將受權數據傳給一個回調頁面,回調頁面需在此域名下,以確保安全可靠。
以上定義彷佛會把人帶入誤區,我一開始被整懵了。配了個回調地址,其實不用,只須要配置受權訪問的域名就ok了,這裏我配置的是testpcenter.shenbianhui.cn。注意,要保證域名可訪問而且要把MP_verify_****.txt放到站點相應的目錄下,不然點擊「確認」按鈕會提示的。
step2:構造微信用戶訪問的url:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb8239ab824d12860&redirect_uri=http://testpcenter.shenbianhui.cn/QRCodeDemo/WeixinJSPay.aspx&response_type=code&scope=snsapi_base&state=1#wechat_redirect
其中,頁面URL中的 scope=snsapi_base 表示應用受權做用域爲不彈出受權頁面,直接跳轉。
這時,咱們在redirect_uri指向的頁面「http://testpcenter.shenbianhui.cn/QRCodeDemo/WeixinJSPay.aspx」程序裏,就可得到get方式的兩個參數值code和state。
step3:根據code獲取openid:
請求url:https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxb8639ab824d12861&secret=0e8d1234fd5345da5ea8e5fab61abcd7&code=02a9bed29b2185a9f0ed3a48fe56e700&grant_type=authorization_code
返回值:{"access_token":"k2iC-Bfce_1ukB1UffUnAB8AnFvGp_8_lvKiMTKF_hILcjjbKpFRrtmWJ5KeWvPOxEu6wsqvT4-oQzYyXVMM__sfTCBJycWupAOLdEXOtrM","expires_in":7200,"refresh_token":"g39EWv6L4Fl7PVo859QPMw_VIMCVMCTco30Lk_-t35QP_mVhQjzvGlXk7MYk8nwkUsc-PxpT2a_kxcel5EAcwv41YizmdH7Hi7o57BIkKj4","openid":"o48_Ct5YigM7JDZ6x3Havr4kgzQQ","scope":"snsapi_base"}
注意,二般狀況下,當code非法時,返回的是{"errcode":40029,"errmsg":"invalid code, hints: [ req_id: 1.Dnsa0402th10 ]"}
程序代碼以下:
public partial class WeixinJSPay : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { tbOpenId.Text = GetOpenIdByCode(); } /// <summary>
/// 微信用戶訪問時,獲取其openid /// </summary>
private string GetOpenIdByCode() { /* * 給微信用戶的請求地址: https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb8239ab824d12860&redirect_uri=http://testpcenter.shenbianhui.cn/QRCodeDemo/WeixinJSPay.aspx&response_type=code&scope=snsapi_base&state=1#wechat_redirect */ LogHelper.Write("--------:" + Request.Url);//示例:http://testpcenter.shenbianhui.cn/QRCodeDemo/WeixinJSPay.aspx?code=001bxIJx1Pi1ge0bZpLx1AAAJx1bxIJb&state=1
string code = Request["code"]; if (string.IsNullOrEmpty(code)) return "未獲取到code參數"; string url = string.Format( "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", "wxb8239ab824d12860", "0e8d4313fd5345da5ea8e5fab61ddae7", code); LogHelper.Write("--------請求openid:" + url); string resultJson = CommonModel.WebCommon.SendStreamStr("", url); LogHelper.Write("--------響應報文:" + resultJson); dynamic model = JsonConvert.DeserializeObject<dynamic>(resultJson); if (model.openid == null) return "未獲取到openid"; return model.openid; } }