單頁面應用在微信服務號下的登入流程
最近我們的小程式涉及到虛擬支付的問題,在ios端的支付被封掉了:innocent:,所以有了在服務號上搞一套H5版的小程式的需求。由於我們小程式是mpvue寫的,為了儘量複用之前的樣式和邏輯,選擇了前後端分離的模式,於是一段新的踩坑之旅開始了。放下wx的jssdk暫且不表,今天來說說登入時遇到的坑。
服務號的登入流程
以前搞過服務號的同學對於它的登入流程應該不陌生,就是當後端檢測到當前使用者沒有授權時,將會重定向到微信的授權頁面,當用戶點選這個授權的button時,微信會根據Url查詢字串中的重定向URL,重新回到我們的頁面。
下面3幅圖展示了整個過程:
-
當我們的伺服器發現使用者沒有授權,返回
302
狀態碼,以及微信的授權頁面location -
使用者在該頁面點選確認登入
-
微信伺服器根據location裡的redirectURL,返回
301
code,重定向回來
上面三步,經歷了兩次重定向,第一次從自己的伺服器重定向到微信的伺服器,微信展示授權頁面。第二次重定向是當用戶點選之後,微信會帶一個code重定向回來,當伺服器拿到這個code之後,經歷一波獲取openId的操作之後,生成一個session,這樣使用者以後訪問時就不需要再次登入。
這樣的模式在傳統的前後端不分離,基於模板的情況下,是沒有問題的,因為沒有json的返回,後端進行邏輯處理後,渲染出html。但是在單頁面的情況下,如果思路跑偏會出現一堆問題。
單頁面遇到的問題
上面說的思路跑偏是什麼意思呢?就是當用戶進來時,先將單頁面的 index.html
發給瀏覽器。當瀏覽器執行開始js指令碼(app.js)時,就會向伺服器傳送請求。
此時如果是一個新使用者在訪問,由於沒有登入,伺服器會返回一個302的重定向狀態碼,然而這次請求是通過ajax發起的。瀏覽器不會自動重定向到授權頁面,導致請求失敗。
此時你會想,瀏覽器不會重定向,我可以當請求失敗時通過設定 window.location
自己重定向到微信授權頁面,這樣解決了第一步的重定向問題,然後當用戶點選確定登入時,馬上又面臨第二個重定向的問題--重定向到哪裡。
由於微信重定向的url是帶著code返回的,重定向的Url肯定不能是一個靜態頁面的Url,必須是一個api,假設還是login。後端在請求中拿到code之後,生成一個新的session,再將原先的html再次返回給瀏覽器,並帶上 set-cookie
欄位,此後瀏覽器會帶著cookie請求,登入至此完成。
這樣做ok,當時卻留下一個很恐怖的URL: https://example.com/login?code=001QLbSQ0Ujc162Sp5UQ0IG6SQ0QLbSD
,此後前端路由開始work,就在前面的基礎上加上一個 #
號,如果你的業務還涉及支付,那就完蛋了,因為支付需要配置的url應該是穩定的而code這個查詢引數是動態變的。
解決方案
我畫了一張圖解釋了重新設計的登入流程:
在這個新的流程中,當新使用者第一次發起請求(login)時,不會返html給瀏覽器,只會進行重定向:
-
如果使用者未登入,重定向到微信的授權頁,並設定redirect url,使使用者點選授權後可以重定向回來
-
新使用者重定向回來之後,login api拿到code,經過生成session操作後,再次重定向到
home
url下 -
如果是老使用者,直接重定向到
home
url下 -
此時由於訪問
home
的使用者都是已登入狀態,api統一返回index.html,所以終端使用者看到的是https://example.com/home
下的頁面,後面的單頁面路由會在這個url下展開。(雖然對服務號使用者來說可能沒什麼區別)
總結一下這麼做的好處:
-
少傳輸一次html頁面,第一種方式一開始就給未登入的使用者傳html是沒用的
-
美觀的url(使用者感知不到)
-
前端無需手動重定向,後端將顯示頁面和登入邏輯放到兩個api中,邏輯更清晰
總結
瞭解到 3xx
狀態碼的博大精深,儘管對普通使用者感知不深,沒有 2xx
受群眾歡迎,也沒有 404
, 500
知名度高,屬於默默無聞型的。但是在網際網路世界裡卻扮演著重要的角色。