原文:https://blog.niceue.com/front-end-development/wechat-h5-payment-process-as-well-as-some-pits.htmljavascript
最近作的 SPA 網站集成了微信支付,使用的是微信 H5 調起支付API接口。作完後對微信 H5 支付的流程有了進一步的瞭解,在先後端調試接口的過程當中也遇到了一些問題,在這裏記錄下來。php
wx.chooseWXPay
發起支付wx.chooseWXPay({ timestamp: '', // 支付簽名時間戳 nonceStr: '', // 支付簽名隨機串 package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***) signType: 'MD5', // 簽名方式 paySign: '', // 支付簽名 })
這裏看起來是 5 步,但其實還少了一步。調用「統一下單」接口的時候須要微信用戶的 openid。html
官方解釋前端
加密後的微信號,每一個用戶對每一個公衆號的 openid 是惟一的。對於不一樣公衆號,同一用戶的 openid 不一樣
這個 openid 只能在微信環境經過重定向拿到。可是在下單的時候用的是 ajax 請求,還用重定向用戶體驗就比較差。因此須要在進入微信的時候就經過重定向拿到 openid 緩存起來,後面就能夠直接使用了。因此入口頁面就要作點小動做。java
官方有OpenID的獲取指引。對於 H5 應用,獲取方式分 3 步走:ajax
後端能夠定義一個 /wechat/redirect
接口,例如:後端
http://yoursite.com/wechat/redirect?url=home_url
用這個地址重定向獲取 code 地址,其中的 url 參數爲最終的重定向地址,在拿到 openid 後跳轉到該 urlapi
接口地址緩存
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirec
接口參數:服務器
appid
: 公衆帳號IDredirect_uri
: 接收 code 的回調地址(請UrlEncode)response_type
: 固定值 codescope
: 應用受權做用域,填 snsapi_base 或者 snsapi_login(可獲取用戶信息,如頭像、暱稱等)state
: 用於保持請求和回調的狀態,防止 csrf 攻擊,可設置爲簡單的隨機數加 session 進行校驗提示:snsapi_login 會跳轉到受權頁讓用戶受權
微信接着會重定向三次,第三次重定向返回到 redirect_uri 地址,而且帶上了 code 參數
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
獲取到 openid 後注意在 session 中緩存起來
在OpenID的獲取指引文檔,請注意黑色標題「微信公衆平臺」和「微信開放平臺」。兩個地方獲取 code 的接口地址不同,但參數是同樣的。最開始後端看錯了文檔使用的是「網站應用微信登陸」文檔裏面提供的獲取 code 的接口,這樣子怎麼都是調不通的。
// 微信公衆平臺是 https://open.weixin.qq.com/connect/oauth2/authorize // 微信開放平臺是 https://open.weixin.qq.com/connect/qrconnect
timeStamp
,而前端調用支付接口使用全小寫 timestamp
微信官方網頁端調起支付API這個接口文檔參數卻誤導觀衆,寫的是駝峯的 timeStamp
後端爲了方便返回給前端的也是 timeStamp,因此在前端須要轉換
解決辦法:
if (!data.timestamp) data.timestamp = data.timeStamp
http://yousite.com/mobile/#!/checkout
以上路徑,iOS 微信識別正確:http://yousite.com/mobile/
而 Android 微信識別出的目錄是:http://yousite.com/mobile/#!/checkout
這應該是 Android 版微信的 Bug
解決辦法是在 #
前添加一個 ?
:http://yousite.com/mobile/?#!/checkout