微信支付趟坑之旅之單頁面應用
年初產品引入了微信支付到現在不到半年的時間,一直沒有過太大的坑爹經歷,自認為微信支付也能hold住了,沒想到上週還是被微信支付團隊的同學狠狠的擺了一道。在這裡留個記錄,希望同入此坑的同學能儘快爬上來。
背景:
上半年上線了商城的微信支付,此專案前端為angularjs 的SPA(single page application,單頁面應用)。地址類似於:http://mall.zjkyz8.com/public/page/index.html。微信支付需要配置一個神奇的支付授權目錄,你需要將專案中的支付地址置於該配置之下,支付方能成功。所以將該配置設為:http://mall.zjkyz8.com/public/page/。 而實際上由於我們的專案前端使用了angularjs。所以實際的支付地址為http://mall.zjkyz8.com/public/page/index.html#/pay-method/0df8398837。
微信對其支付授權目錄的配置規則描述如下:
- 1、所有使用公眾號支付方式發起支付請求的連結地址,都必須在支付授權目錄之下;
- 2、最多設定3個支付授權目錄,且域名必須通過ICP備案;
- 3、頭部要包含http或https,須細化到二級或三級目錄,以左斜槓“/”結尾。
其中併為對是否允許特殊字元做特別描述(此處特殊字元指#),但實際據客服講是不允許的,也就是說對SPA,支付目錄是無法配置到細化的目錄的。不過沒關係,這樣的配置微信支付是可以正常工作的。目前為止,一切正常。
問題:
下面我們來說說問題是什麼。這兩天做了個列表頁,將一些推廣活動放在一起,需求要求使用者通過這個列表頁點選某個商品也可以完成購買。平衡功能分離與複用後,實現瀏覽購買流程如下:http://mall.zjkyz8.com/public/page/list.html(列表頁) ->http://mall.zjkyz8.com/public/page/list.html#/detail/83984775(商品詳情頁)->http://mall.zjkyz8.com/public/page/index.html#/create-order/83984775(下單頁)->http://mall.zjkyz8.com/public/page/index.html#/pay-method/0df8398837(支付頁)
分析:
很奇怪,微信錯誤資訊中提及的URL並不是發起支付的頁面,而是下單頁。更奇怪的是整個下單支付邏輯完全是複用商城中已有邏輯,並未做任何修改,但測試後發現商城中的功能正常。於是通過郵件聯絡微信支付技術支援(郵件啊,親,效率那是要多低有多低),客服一口咬定是SPA的中的雜湊路由的問題,移除以後就沒有問題。雖然我反覆強調之前的功能同樣帶著這部分,但是卻可以支付成功,但客服同學完全忽略這個觀點,只是不停強調是這個問題。最後事實證明客服的這個說法是正確的,但是原因卻讓人哭笑不得。
原因:
客服溝通失敗,只能靠自己了。折騰了一星期,反覆google。最後終於找到原因。文末會新增給了我巨大幫助的一篇文章,感興趣的小夥伴可以看一下。這個問題的產生實際是兩個原因共同作用的結果:
解決方案:1. 當微信支付被調起時,微信自己會驗證當前調起微信支付的頁面URL是否與微信支付授權目錄匹配。那麼何為調起微信支付頁面的URL呢,嘿嘿,並不是window.location.href這麼簡單。這個URL實際是最後一次引起頁面重新整理的URL。迴歸到我們的專案,商城端的這個URL實際是http://mall.zjkyz8.com/public/page/index.html,因為只有第一次開啟商城時也就是點選了連結後會引起全頁面重新整理,而之後的所有操作均是SPA內部的路由變換,只會引起雜湊變化,頁面部分重新整理。而新的這個列表頁比較複雜,因為有了複用,使用者在點選下單後會跳轉下單頁,即http://mall.zjkyz8.com/public/page/list.html#/detail/83984775(商品詳情頁)->http://mall.zjkyz8.com/public/page/index.html#/create-order/83984775(下單頁),SPA發生了切換,從list.html切換到了index.html,這時候微信會重新獲取調起微信支付的頁面URL,正好這次變換是帶著雜湊部分的,所以微信會連著雜湊部分一起取過來比較。這正好解釋了為什麼微信報錯的URL不是當前URL。
2. 比較過程就比較有意思了,這部分內容由於無法接觸到微信的檢查邏輯,所以基本上是自己根據現象猜的,各位小夥伴可以自行選擇與理解。大概的邏輯可能是取到URL後用最後一個'/'做分隔符,將URL分為兩部分,用第一部分和配置的支付授權目錄做比對,匹配則驗證成功,否則驗證失敗。很顯然,這種驗證方式下,URL分隔後的第一部分會包含雜湊,於是驗證失敗。
既然知道了微信獲取支付頁面URL不能支援雜湊部分,那麼想辦法把雜湊部分幹掉。方法很簡單粗暴,在#前加個?。哈哈,既然你微信不想支援SPA的雜湊,那你總得支援查詢引數吧。而且既然不支援雜湊,估計也沒想著URL中會出現雜湊,那麼他們的邏輯就會寫成在分隔URL前先來步預處理,將查詢引數幹掉,估計也是簡單的用?分隔,取第一部分。
寫在最後:
經過驗證,這個解決方案是可行的。這也從一個側面反映出很多人對於URL的理解以及對程式碼相容性的理解。URL中的雜湊部分並不是一個新的技術。我想如果我換為錨點大家就一定有印象了。這個東西最早被應用於頁面內定位到某個DOM節點。後來在SPA中被用來做路由。很顯然,微信在做支付功能時完全沒有考慮這個技術,雖然我們可以說已經很少使用錨點了。但是單頁面應用的普及卻在逐步提高。換個角度,我覺得既然查詢引數已經能夠支援了,那麼再支援一個雜湊並不是什麼困難的事情吧。10分鐘的開發時間加半小時的測試時間換來的是對整個SPA的友好支援,應該不吃虧啊。
最後的最後,提出一個我的疑問。我始終無法理解微信支付中授權支付目錄的業務價值在哪裡。聽名字像是嘗試解決安全問題。但是整個JSSDK是基於網站域名的,這還不夠嗎?真誠地希望瞭解的同學來普及一下。
附上對我幫助巨大的文章地址:http://www.kejik.com/article/152868.html。 不知道為什麼chrome訪問這個地址,會報有安全隱患,請小夥伴們自行斟酌吧 :) 。