動態(tài)頁面的瀏覽器緩存
我們知道,對于WEB頁面中的JS和CCS,并不會每次都請求完整的內(nèi)容,有時候會直接利用本地的緩存;而對頁面本身,卻往往會去加載完整內(nèi)容,對于服務(wù)器來說可能每次也要生成完整的內(nèi)容,并送到客戶端;同樣的,對于一些http接口,每次調(diào)用也會去重新生成數(shù)據(jù),瀏覽器也會重新加載完整的數(shù)據(jù);
但有這樣一些頁面,雖然是動態(tài)的但變動頻率較小,且對于同一用戶重復(fù)調(diào)用可能很多(比如說個人管理后臺或者新聞首頁面),我們希望像js或者ccs那樣在客戶端緩存起來.并且,在我們希望的時候,可以更新客戶端備份的那個頁面,或者接口數(shù)據(jù).是否可以做到呢;
事實上,瀏覽器可以緩存js,就一定能緩存我們的動態(tài)頁面;
先研究下js是如何緩存起來的:
用firebug看一下js的加載:
先強刷(ctrl+F5)一下 http://ilab.iteye.com/ 頁面,觀看js的加載如圖

狀態(tài)為200 , 查一下200的含意 :
請求成功(其后是對GET和POST請求的應(yīng)答文檔。)
這是對js文件的完整加載;
再直接F5刷新下 http://ilab.iteye.com/ ,觀看js的加載如圖

狀態(tài)為304,再查一下304的含意:
未按預(yù)期修改文檔??蛻舳擞芯彌_的文檔并發(fā)出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)。服務(wù)器告訴客戶,原來緩沖的文檔還可以繼續(xù)使用。
此時其實并沒有從服務(wù)端加載完整文件而是去讀的本地緩存;
從304的描述來看,我們知道,請求依然發(fā)出,并由服務(wù)端告知瀏覽器,掉用緩存;
我們可以總結(jié)出兩點:
1.
由于服務(wù)端只是返回簡單的頭信息,并沒有生成完整頁面,所以雖然請求依然發(fā)出,對于瀏覽器和服務(wù)器來說都更快更輕松了;
2.
我們可以控制瀏覽器去更新緩存;)
具此,我們可以得出結(jié)論,對于某此動態(tài)頁面來說,完全可以充分利用瀏覽器緩存來降低服務(wù)器壓力,提升客戶端速度;
----------------------------------分隔線 ----------------------------------------
現(xiàn)在我們來看下要怎么做;
由于對文檔的描述在http頭信息中,并且依據(jù)304的描述,我們知道,這個屬性和 Modified Time有關(guān),我們比對下普通的頁面和js的頁面的respose的頭信息的不同:

我們發(fā)現(xiàn),多了個Last-Modified的屬性;
再比對請求,

發(fā)現(xiàn),多了If-Modified-Since;
武斷的推測一下(或者認(rèn)真的讀下http協(xié)議的文檔):我們可以這樣認(rèn)為:
1.第一次請求成功返回202;
2.假如返回頭信息有Last-Modified屬性 則存入瀏覽器緩存;
3.再次請求,假如請求的為緩存頁面,則頭信息中加入 If-Modified-Since;
4.服務(wù)端通過If-Modified-Since(即上次響應(yīng)中Last-Modified的值)來判斷是否需要更新,否的話返回304;
5.假如返回304,則瀏覽器則讀緩存;

按照這個原理我們通過 HttpServletResponse, HttpServletRequest來償試實現(xiàn)下:
對任意一個頁面先來句
Java代碼
- getResponse().addHeader("Last-Modified", "hello kitty");
然后再次請求該頁面時,我們就可以發(fā)現(xiàn)請求中就有了 If-Modified-Since 屬性
Java代碼
- getRequest().getHeader("if-modified-since");
通過這句代碼,拿到具體值;
假如判斷為不用更新則直接返回304
Java代碼
- getResponse().setStatus(HttpServletResponse.SC_NOT_MODIFIED);
并且立即結(jié)束返回,不用繼續(xù)執(zhí)行;
對于取到的if-modified-since,即是上次存入的Last-Modified,里面的值到是可以很隨意,你除了放時間,也可以放memberId;
--------------------------------分隔線 ----------------------------------
實現(xiàn)問題也解決了;
最后一個問題,是怎么保證接口,或者頁面的動態(tài)性;也就是說怎么通過Last-Modified或者if-modified-since來判斷頁面不需要更新;
考慮最簡單的情況,這個接口或者頁面僅提供和用戶相關(guān)的不同信息,并且該信息一但建立則不會改變;
那對于此接口,假如參數(shù)中包含memberId屬性,則一但具有if-modified-since值,則永遠(yuǎn)返回304;因為對于不同url,瀏覽器均會進(jìn)行緩存;
假如memberId屬性在cookie中,url一致,那么,在Last-Modified中存入memberId,判斷時于cookie或者session中url比對,相同則認(rèn)為是正確的緩存返回304;
現(xiàn)在,新的問題來了,用戶的相關(guān)信息更新了;
假如這個更新頻率不是那么頻繁,那么想辦法做個更新機制還是合理的;你需要一個地方在服務(wù)端記錄用戶接口信息的版本號了,從if-modified-since中取得上次的版本號,然后進(jìn)行比對,如果相同,則返回304;
在某些情況下,獲取更新記錄信息要比計算合成完整信息并利用帶寬將數(shù)據(jù)傳給客戶端代價小得多,此時你可以試下WEB服務(wù)動態(tài)接口的靜態(tài)緩存;
【編輯推薦】