1. HTTP本身無連接無狀態(tài), 如何在不同請(qǐng)求間識(shí)別用戶以支持需要多個(gè)請(qǐng)求才能完成的業(yè)務(wù)?
其它所有問題都是這個(gè)問題的某種解決方案引入的. 這個(gè)論斷有一個(gè)推論,
就是不需要識(shí)別用戶的Web應(yīng)用是最簡(jiǎn)單的Web應(yīng)用.
一種方案是所有的業(yè)務(wù)都設(shè)計(jì)成一次請(qǐng)求就可以完成, 比如讓用戶每次都輸入用戶名密碼, 填寫所有的表單,
然后一次性提交. 從用戶體驗(yàn)的角度顯然不可行...
狀態(tài)保存
需要保存狀態(tài)的原因是要在無連接的協(xié)議上模擬有連接的用戶體驗(yàn)
狀態(tài)保存的地點(diǎn)無非是客戶端或者服務(wù)端, 以及URL本身
客戶端一般是cookie, 類似Hash的鍵值對(duì). 存放小塊數(shù)據(jù), 通常是真正狀態(tài)的某種標(biāo)識(shí),
可加密, 可設(shè)置有效期及適用的域, 由瀏覽器每次請(qǐng)求時(shí)發(fā)送給服務(wù)端. cookie的問題在于, 有些用戶在瀏覽器中禁止了對(duì)cookie的支持,
然而實(shí)際上有什么類型的網(wǎng)站需要考慮/考慮了這類用戶? 以及安全性(可被拷貝偷走放在自己機(jī)器上以假冒其他用戶用).
可對(duì)cookie加密或摘要來保證數(shù)據(jù)的機(jī)密性和完整性
服務(wù)端存儲(chǔ)有內(nèi)存和外部存儲(chǔ). 一般把跨越多次請(qǐng)求維護(hù)特定客戶端的狀態(tài)數(shù)據(jù)的場(chǎng)所叫做Session.
Session并不是HTTP本身的概念, 而是各開發(fā)包實(shí)現(xiàn)者提供的概念和實(shí)現(xiàn), 通過唯一的session
id(通常通過cookie保存)在不同的請(qǐng)求間關(guān)聯(lián)數(shù)據(jù).
Session放在內(nèi)存中的問題是無法適應(yīng)負(fù)載平衡和可靠性的需求, 優(yōu)點(diǎn)是性能; 外部存儲(chǔ)恰好相反;
各種不同的開發(fā)包對(duì)Session的實(shí)現(xiàn)一般都支持存儲(chǔ)可配置, 對(duì)應(yīng)用"透明"(實(shí)際上無法完全透明, 比如如果需要持久化Session到外部存儲(chǔ),
則需要內(nèi)存對(duì)象支持某種形式的可序列化, 而如果只是放在內(nèi)存里則無此需求)
URL本身可攜帶數(shù)據(jù), 問題是應(yīng)用程序開發(fā)者需要仔細(xì)維護(hù)URL的產(chǎn)生和解析. 開發(fā)包提供了支持,
可定義URL到對(duì)應(yīng)處理程序的映射, 解碼URL中攜帶的數(shù)據(jù)并作為參數(shù)傳遞給處理程序.
-
URL和cookie都適合存放小片數(shù)據(jù). 那么什么類型的數(shù)據(jù)適合放進(jìn)URL,
什么數(shù)據(jù)適合放進(jìn)cookie呢? 從URL的語義上來說, 編碼進(jìn)URL的數(shù)據(jù)應(yīng)該是所請(qǐng)求資源的某種屬性, 而cookie一般存放用戶的某種標(biāo)識(shí)數(shù)據(jù).
也就是URL應(yīng)該是業(yè)務(wù)相關(guān)數(shù)據(jù), cookie應(yīng)該是應(yīng)用相關(guān)數(shù)據(jù). 當(dāng)瀏覽器禁用cookie時(shí), 開發(fā)包支持把session
id之類的數(shù)據(jù)編碼進(jìn)URL.
-
Session存放需要頻繁用到的數(shù)據(jù), 用戶相關(guān)而業(yè)務(wù)無關(guān)的.
關(guān)鍵的業(yè)務(wù)數(shù)據(jù)要及時(shí)持久化到外部存儲(chǔ). 業(yè)務(wù)相關(guān)數(shù)據(jù)一般按需存取...
狀態(tài)清除
狀態(tài)清除是由狀態(tài)保存引入的問題, 確切的說是對(duì)保存狀態(tài)的資源的回收和重利用.
另外是減少安全性方面的隱患.
客戶端cookie有過期時(shí)間, 也可在用戶登出的時(shí)候主動(dòng)設(shè)置其過期來刪除
服務(wù)端Session可在用戶登出的時(shí)候主動(dòng)刪除, 開發(fā)包也會(huì)檢測(cè)同樣的Session ID訪問間隔,
如果超過某個(gè)設(shè)定的時(shí)間沒有包含某個(gè)Session ID的cookie被送到服務(wù)端, 則自動(dòng)清除對(duì)應(yīng)Session數(shù)據(jù). 這時(shí)候表現(xiàn)為如果用戶長(zhǎng)時(shí)間不操作,
下次操作時(shí)將被開發(fā)包重定向到登錄頁面.
業(yè)務(wù)數(shù)據(jù)的傳遞
數(shù)據(jù)的輸入和處理發(fā)生在不同的主機(jī)上, 是Web應(yīng)用的天然特質(zhì). HTML的Form和隱藏字段,
HTTP Post專為此設(shè)計(jì). 另外URL本身也可以承載一些業(yè)務(wù)數(shù)據(jù)(HTTP Get)
跨頁面的業(yè)務(wù)數(shù)據(jù)傳遞, 一般通過持久化到外部存儲(chǔ)的方式來共享. 應(yīng)用數(shù)據(jù)則可以通過Session,
一些細(xì)分的概念如臨時(shí)數(shù)據(jù),
只用一次的數(shù)據(jù)等,
開發(fā)包都有支持, 一般也是背后通過Session實(shí)現(xiàn)
2. 客戶端狀態(tài)更新
HTTP的無連接帶來的第二個(gè)問題是服務(wù)端無法主動(dòng)把信息推給客戶端,
另一個(gè)原因是客戶端通常沒有public的IP. 客戶端只能使用按需請(qǐng)求或輪詢模型. 此題無解. 如果是企業(yè)內(nèi)部系統(tǒng)集成, 考慮使用消息隊(duì)列等方式.
3. 并發(fā)
并發(fā)是要處理的第三個(gè)本質(zhì)問題. 對(duì)并發(fā)(背后是狀態(tài)一致性與完整性)的解決會(huì)帶來事務(wù),
事務(wù)會(huì)帶來性能問題, 對(duì)性能的解決會(huì)帶來Cache等方案, Cache則會(huì)引入狀態(tài)一致性與完整性問題...回到起點(diǎn).
最終是狀態(tài)的一致性與完整性和性能之間的某種折衷.
Cache的一種實(shí)現(xiàn)是將動(dòng)態(tài)頁面轉(zhuǎn)化為一段時(shí)間內(nèi)的靜態(tài)頁面, 交給Web服務(wù)器直接處理,
減輕應(yīng)用服務(wù)器的負(fù)擔(dān).
應(yīng)用服務(wù)器內(nèi)的Cache一般是key value pair. key一般是url, 查詢語句,
對(duì)象ID等.
Cache的實(shí)現(xiàn)要考慮的問題主要是Cache的生命周期, 是請(qǐng)求內(nèi), 會(huì)話內(nèi), 還是應(yīng)用程序范圍.
以及同步問題, 何時(shí)刷新, 如何刷新.
-
HTTP Request范圍內(nèi)的Cache, 和通常的事務(wù)策略配合良好.
事務(wù)通常不會(huì)超出一次請(qǐng)求, 隔離級(jí)別是可讀到其它事務(wù)提交后的內(nèi)容, 不會(huì)讀到其它事務(wù)提交前的改動(dòng)(?). 這類Cache邊界清晰,
幾乎不會(huì)有失效刷新的需求, 基本不需要考慮多線程的問題(每個(gè)請(qǐng)求一般獨(dú)占一個(gè)處理線程). 缺點(diǎn)是對(duì)性能提高有限,
如果一次請(qǐng)求范圍內(nèi)對(duì)同一資源的訪問很少超過一次的話.
-
Session范圍內(nèi)的Cache...什么類型的數(shù)據(jù)適合放到Session級(jí)別的Cache呢?
Session通常包含多個(gè)事務(wù), 如果放業(yè)務(wù)數(shù)據(jù)到Cache, 毫無疑問要經(jīng)常刷新, 失去Cache的意義. 刷新時(shí)有多線程的問題,
尤其對(duì)AJAX應(yīng)用. 如果是不經(jīng)常變化的應(yīng)用數(shù)據(jù), 通常放到應(yīng)用程序級(jí)別的Cache. Session內(nèi)的數(shù)據(jù)基本可看作已經(jīng)是某種緩存...
-
Application范圍內(nèi)的數(shù)據(jù), 一般存放不經(jīng)常變化的配置數(shù)據(jù), 數(shù)據(jù)字典等.
刷新可以是定時(shí)輪詢, 及各種基于事件的手段: HTTP Get/Post, 消息隊(duì)列等
4. 驗(yàn)證
這里說的驗(yàn)證是Validation, 不是Authentication.
Authentication/Authorization并非Web特定問題, 其它類型的應(yīng)用面臨同樣的問題, 有相似的解決方案
Validation則是Web相關(guān), 蓋因輸入與處理發(fā)生在不同的主機(jī)上,
驗(yàn)證邏輯發(fā)生的位置和時(shí)機(jī)都是需要考慮的因素
-
一條底線是在數(shù)據(jù)被正式接受之前, 比如存到數(shù)據(jù)庫之前, 用來進(jìn)行業(yè)務(wù)計(jì)算之前, 進(jìn)行驗(yàn)證,
以確保數(shù)據(jù)的合法性. 這在大多數(shù)情況下都是必要的. 然而從用戶體驗(yàn)的角度講, 時(shí)間有點(diǎn)晚, 并且驗(yàn)證產(chǎn)生的錯(cuò)誤信息可能更偏向于實(shí)現(xiàn),
而不是用戶能理解的業(yè)務(wù)含義, 并不必要的向用戶暴露實(shí)現(xiàn)細(xì)節(jié). 所以需要其它的驗(yàn)證手段作為補(bǔ)充
-
一種方式是在客戶端用JavaScript進(jìn)行驗(yàn)證, 不必讓數(shù)據(jù)到服務(wù)器走一個(gè)來回,
帶來的問題是部分驗(yàn)證邏輯在客戶端和服務(wù)端用不同的語言寫兩遍.
-
一個(gè)改進(jìn)是利用AJAX即時(shí)驗(yàn)證, 既改善了用戶體驗(yàn),
又避免了用JavaScript重寫驗(yàn)證邏輯
即時(shí)的驗(yàn)證一般關(guān)注于基礎(chǔ)合法性的驗(yàn)證, 比如格式, 必填字段等.
數(shù)據(jù)的業(yè)務(wù)合法性則一般在提交后由服務(wù)端進(jìn)行全面驗(yàn)證
5. 開發(fā)效率
開發(fā)包對(duì)Web問題的各種解決方案進(jìn)行了封裝, 分離關(guān)注點(diǎn), 使開發(fā)人員更關(guān)注業(yè)務(wù)邏輯,
開發(fā)包處理了所有與Web相關(guān)的應(yīng)用邏輯
為使這一切對(duì)開發(fā)者透明, 結(jié)合Web應(yīng)用的Request/Response模型,
開發(fā)包一般采用管道和過濾器模式來動(dòng)態(tài)的,可配置的將各種服務(wù)插入到數(shù)據(jù)的處理流程中.
比如Session的管理, 包括通過cookie識(shí)別特定客戶端和清除過期數(shù)據(jù)等邏輯,
都透明的發(fā)生在請(qǐng)求經(jīng)過的路徑上. Session數(shù)據(jù)本身的存儲(chǔ)位置, 也都是可配置的. 其它的例子包括頁面緩存和用戶驗(yàn)證等.
-
封裝HTTP協(xié)議字節(jié)流到特定開發(fā)平臺(tái)的對(duì)象, 通常是能以key-value
pair的形式訪問的接口. 更有細(xì)粒度的對(duì)象如Cookie等概念的封裝
-
封裝URL到對(duì)應(yīng)處理程序的映射, 包括組裝URL, 將URL參數(shù)解析成具有業(yè)務(wù)含義的數(shù)據(jù).
開發(fā)者可定制映射規(guī)則
-
封裝Form/Request數(shù)據(jù)到業(yè)務(wù)對(duì)象的轉(zhuǎn)換, 通常稱之為Binder
-
通過MVC分離視圖邏輯和業(yè)務(wù)邏輯, 并且通過模板視圖技術(shù)支持UI開發(fā)者和業(yè)務(wù)開發(fā)者的分工協(xié)作
-
提供了過濾器接口, 可以自定義驗(yàn)證, 授權(quán), 錯(cuò)誤處理等邏輯