原文:https://blog.niceue.com/front-end-development/wechat-h5-payment-process-as-well-as-some-pits.html
最近做的 SPA 網站集成了微信支付,使用的是微信 H5 調起支付API接口。做完后對微信 H5 支付的流程有了進一步的了解,在前后端調試接口的過程中也遇到了一些問題,在這里記錄下來。
支付流程
- 在訂單頁 ajax 請求后端發起下單,后端掛起請求
- 后端根據訂單號結合微信支付相關配置參數向微信服務器發起統一下單
- 下單成功,微信通知前面傳遞的 notify_url,返回 prepay_id (預支付交易會話標識)
- 后端返回前端 JSAPI 調用的參數
- 前端使用 JSSDK 的
wx.chooseWXPay
發起支付
wx.chooseWXPay({ timestamp: '', // 支付簽名時間戳 nonceStr: '', // 支付簽名隨機串 package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***) signType: 'MD5', // 簽名方式 paySign: '', // 支付簽名 })
這里看起來是 5 步,但其實還少了一步。調用“統一下單”接口的時候需要微信用戶的 openid。
openid 是什么?
加密后的微信號,每個用戶對每個公眾號的 openid 是唯一的。對於不同公眾號,同一用戶的 openid 不同
這個 openid 只能在微信環境通過重定向拿到。但是在下單的時候用的是 ajax 請求,還用重定向用戶體驗就比較差。所以需要在進入微信的時候就通過重定向拿到 openid 緩存起來,后面就可以直接使用了。所以入口頁面就要做點小動作。
獲取 openid
官方有OpenID的獲取指引。對於 H5 應用,獲取方式分 3 步走:
1. 后端重定向到獲取 code 接口
后端可以定義一個 /wechat/redirect
接口,例如:
http://yoursite.com/wechat/redirect?url=home_url
用這個地址重定向獲取 code 地址,其中的 url 參數為最終的重定向地址,在拿到 openid 后跳轉到該 url
2. 獲取 code:
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 參數
3. 通過 code 獲取 openid 和 access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
獲取到 openid 后注意在 session 中緩存起來
一些需要注意的坑
1. 獲取 code 的接口地址
在OpenID的獲取指引文檔,請注意黑色標題“微信公眾平台”和“微信開放平台”。兩個地方獲取 code 的接口地址不一樣,但參數是一樣的。最開始后端看錯了文檔使用的是“網站應用微信登錄”文檔里面提供的獲取 code 的接口,這樣子怎么都是調不通的。
// 微信公眾平台是
https://open.weixin.qq.com/connect/oauth2/authorize
// 微信開放平台是
https://open.weixin.qq.com/connect/qrconnect
2. 后端簽名用 timeStamp
,而前端調用支付接口使用全小寫 timestamp
微信官方網頁端調起支付API這個接口文檔參數卻誤導觀眾,寫的是駝峰的 timeStamp
后端為了方便返回給前端的也是 timeStamp,所以在前端需要轉換
解決辦法:
if (!data.timestamp) data.timestamp = data.timeStamp
3. iOS 和 Android 版微信對“支付授權目錄”的檢測不同
http://yousite.com/mobile/#!/checkout
以上路徑,iOS 微信識別正確:http://yousite.com/mobile/
而 Android 微信識別出的目錄是:http://yousite.com/mobile/#!/checkout
這應該是 Android 版微信的 Bug
解決辦法是在 #
前添加一個 ?
:http://yousite.com/mobile/?#!/checkout