最近選用了 React + React-Router 的技術(shù)棧,自然而然走了 SPA 的路線六剥,下面總結(jié)下在所謂的 SPA 下的一些技術(shù)點(diǎn)的坑。
登錄態(tài)的維持
現(xiàn)有方案
登錄頁(yè)面發(fā)起 Ajax 請(qǐng)求獲得用戶 token惶洲,把 token 存放在 localStorage 里面抓督,然后通過前端路由跳轉(zhuǎn)到用戶主頁(yè)。隨后用戶相關(guān)的請(qǐng)求都會(huì)在 http head 里面帶上這個(gè) token邑贴。服務(wù)器端只負(fù)責(zé)驗(yàn)證每次請(qǐng)求中 token 的合法性(譬如:是否過期)席里。遇到的問題
把 token 保存在 localStorage 中主要考慮用戶打開瀏覽器多個(gè) tab 頁(yè)可以維持登陸態(tài)。但是存儲(chǔ)在 localStorage 里面的 token 面臨如下問題:
- 被串改的風(fēng)險(xiǎn)比較大拢驾,一旦被篡改奖磁,可以跨用戶操作。
- 多賬號(hào)登錄相互覆蓋 localStorage 中 token 的問題繁疤。
- 解決方案
針對(duì)多賬號(hào)登錄相互覆蓋的問題咖为,現(xiàn)有采取的方案是在登錄后分別在內(nèi)存和 localStorage 里面保存一份 token,每次要用到 token 的時(shí)候都去對(duì)比一下嵌洼,如果檢測(cè)到不一樣則提示用戶關(guān)閉當(dāng)前窗口防止串號(hào)案疲。這么做的目的一來防止用戶自己被多個(gè)賬號(hào)誤導(dǎo),二來如果關(guān)閉了檢測(cè)到串號(hào)的窗口麻养,不影響后登錄的那個(gè)賬號(hào)使用(當(dāng)然如果前一個(gè)窗口不關(guān)閉也沒有問題褐啡,js 使用的始終是內(nèi)存中的 token)。
但是當(dāng)同一個(gè)用戶開多個(gè)窗口鳖昌,那么新開的窗口中的 token 第一次獲取就只能從 localStorage 里面獲取备畦。這時(shí)就有 token 被篡改可以跨用戶操作的風(fēng)險(xiǎn)。針對(duì)這個(gè)風(fēng)險(xiǎn)我預(yù)想了解決方案(需要用到 session 存儲(chǔ) token):-
在已經(jīng)登錄一個(gè)賬號(hào)的情況下许昨,不允許開新瀏覽器窗口進(jìn)行其他賬戶的登錄懂盐,即如果檢測(cè)到當(dāng)前已經(jīng)是登錄態(tài)則不允許用戶停留在登錄頁(yè)。
singleuser -
在已經(jīng)登錄一個(gè)賬號(hào)的情況下糕档,允許開新瀏覽器窗口進(jìn)行其他賬戶的登錄莉恼。
multiuserlogin
這種情況下如果登錄了第二個(gè)賬戶,第一個(gè)窗口(第一個(gè)賬號(hào))要再進(jìn)行任何操作,傳回的 token 就和 server session 中的 token 不匹配俐银,server 就可以返回狀態(tài)碼讓前端把用戶登出尿背。
-
多路由模塊共享數(shù)據(jù)同步問題
如果多路由之間有相關(guān)的業(yè)務(wù)數(shù)據(jù),那么為了減少請(qǐng)求捶惜,提高用戶體驗(yàn)田藐,最好把多路由相關(guān)的數(shù)據(jù)共同抽象到一個(gè)地方,譬如 redux 的 store 里面吱七。這樣一個(gè)路由改了數(shù)據(jù)汽久,當(dāng)切換到另一個(gè)路由就不需要從后臺(tái)再拉一遍數(shù)據(jù)的最新狀態(tài)。這點(diǎn)對(duì)于單人開發(fā)沒有問題踊餐,但是對(duì)于多人協(xié)作就需要提前設(shè)計(jì)數(shù)據(jù)存放結(jié)構(gòu)景醇,約定接口。一邊做一邊改就容易出現(xiàn)溝通問題吝岭,數(shù)據(jù)架構(gòu)也不容易統(tǒng)一啡直。
異步任務(wù)的狀態(tài)問題
針對(duì)有異步任務(wù)的情況就要考慮狀態(tài)更新的問題。因?yàn)轫?yè)面提交了一個(gè)請(qǐng)求修改數(shù)據(jù)苍碟,但是數(shù)據(jù)被修改的最新狀態(tài)無(wú)法立即體現(xiàn)在當(dāng)前界面上酒觅,那么就會(huì)有如下問題:
- 頁(yè)面如何處理中間態(tài)即處理中的狀態(tài)提示。
- 頁(yè)面是否需要接入服務(wù)器推送微峰,等異步任務(wù)完成后把結(jié)果推送到頁(yè)面來更新狀態(tài)舷丹。
- 異步任務(wù)還沒有完成,用戶刷新了頁(yè)面并又提交了相同的任務(wù)如何處理蜓肆。
問題1如果中間態(tài)存儲(chǔ)在前端颜凯,一旦用戶刷新頁(yè)面或者新開頁(yè)面就轉(zhuǎn)換成問題3了,所以后臺(tái)一定要做好驗(yàn)證仗扬,前端無(wú)法嚴(yán)格維持狀態(tài)症概。還有一種情況就是后端存儲(chǔ)中間態(tài),那么無(wú)論是刷新還是新開頁(yè)面用戶都能夠看到中間態(tài)也會(huì)避免提交重復(fù)請(qǐng)求早芭,但是這種方案就增加了后端的復(fù)雜度彼城,需要根據(jù)項(xiàng)目的需求自行決定。
問題2涉及兩個(gè)方面:一來是接入推送服務(wù)增加復(fù)雜度的問題退个,需要酌情考慮募壕。二來是提高用戶體驗(yàn)的問題如果最新的狀態(tài)需要及時(shí)通知到用戶,那么推送方案就要在技術(shù)選型時(shí)考慮在內(nèi)语盈。
多人操作同份數(shù)據(jù)
這個(gè)問題最典型的就是項(xiàng)目管理工具舱馅,針對(duì)同一個(gè)任務(wù)兩個(gè)人同時(shí)開著界面,如果一個(gè)人認(rèn)領(lǐng)了刀荒,那么另一個(gè)人一般情況下是無(wú)法知道的代嗤,可能會(huì)造成“誤操作”棘钞。這個(gè)時(shí)候增加推送功能能極大的提高用戶體驗(yàn)。