瀏覽器緩存內幕及解決方案
- 瀏覽器緩存內幕及解決方案
- 在下面三種不同的情況下,瀏覽器的緩存情況不同:
- 1).Servlet沒有覆蓋getLastModified方法,響應消息中無LastModified頭字段,在瀏覽器緩存的文檔無“上次修改時間”.
- 2).有getLastModified方法,響應消息中有LastModified頭字段,但返回時間晚于緩存文檔“上次修改時間”
- 3).有getLastModified方法,響應消息中有LastModified頭字段,但返回時間早于等于緩存文檔“上次修改時間”
- 后退、前進、轉到(手工輸入后按回車) 通過超鏈接訪問 刷新
- 1)不發請求,直接使用緩存 發出請求 發出請求
- 2)不發請求,直接使用緩存 不發請求 發出請求,返回200
- 3)不發請求,直接使用緩存 不發請求 發出請求,返回304
- 2、如何禁止Servlet的緩存?(張老師JavaWeb書第236頁)
- Java代碼
- response.setDateHeader("Expires", 0);
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- response.setDateHeader("Expires", 0);
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- 3、如何禁止JSP頁面的緩存?
- Html代碼
- response.setDateHeader("Expires", 0);
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- < http-equivhttp-equiv="pragma" content="no-cache">
- < http-equivhttp-equiv="cache-control" content="no-cache">
- < http-equivhttp-equiv="expires" content="0">
- response.setDateHeader("Expires", 0);
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- < http-equiv="pragma" content="no-cache">
- < http-equiv="cache-control" content="no-cache">
- < http-equiv="expires" content="0">
- 4、如何禁止靜態頁面的緩存?(張老師JavaWeb書第238頁)
- Html代碼
- < http-equivhttp-equiv="pragma" content="no-cache">
- < http-equivhttp-equiv="cache-control" content="no-cache">
- < http-equivhttp-equiv="expires" content="0">
- < http-equiv="pragma" content="no-cache">
- < http-equiv="cache-control" content="no-cache">
- < http-equiv="expires" content="0">
- 靜態頁面被禁止后,刷新瀏覽器返回304
- JSP頁面被禁止后,刷新瀏覽器返回200
- web開發中的緩存問題的研究
- 一般情況下,瀏覽器都會緩存已經訪問過的頁面內容,關于如何禁止瀏覽器緩存的介紹,在網上到處都有相關的文章,但是,關于瀏覽器如何利用緩存,如何處理緩存的講解,卻鮮有人談及。我一直為這個問題所困惑,這個問題也是絕大多數有經驗的WEB開發人員所共同面臨的問題,我有些朋友已做過幾十個大大小小的WEB項目,當與他們交流這些問題時,他們雖然也在項目中遇到和解決過這些問題,但由于沒有足夠的時間和精力來仔細思考這些問題的原因和細節,他們對這些問題始終也是一知半解、含糊不清,而目前又很少關于這些問題的專門和詳細講解,我最近用了兩天的時間,把瀏覽器緩存的問題透徹地研究了一翻,主要包括一下方面的細節。
- 1 如何禁止瀏覽器緩存,這是最簡單的問題,本來羞于在此講解,但是為了完整性,不妨將其列為一個知識點。
- 2 瀏覽器在訪問已緩存過的資源時,它在什么情況下會向服務器發送請求?在什么情況下根本就不向服務器發送請求。這與瀏覽器的緩存設置有關!但是,由于幾乎所有人的瀏覽器都是采用的默認設置,所以,重點應該放在分析瀏覽器的默認緩存設置的研究上。
- 3 當通過其他網頁文檔中的超鏈接來訪問某一個已經緩存過的資源時,瀏覽器是否要向服務器發出訪問請求?如果不發,則會出現一個問題:當銷售一件商品后再回到商品庫存的顯示頁面時,看到的還將是先前看到的內容,而不是更新的庫存數據。但是,在訪問一個普通的HTML文件時,如果瀏覽器每次都向服務器發送訪問請求,效率就會相對低下,這就失去了緩存的意義和價值。所以,結論應是瀏覽器訪問動態頁面時不能使用緩存,而訪問靜態頁面時應該使用緩存,但是,僅僅根據被訪問頁面的資源名稱,瀏覽器是無法知道商品庫存的顯示頁面是屬于動態內容,還是屬于靜態內容。瀏覽器是根據什么方式來判斷它緩存的資源是動態的,還是靜態的呢?在什么請求下,它會對緩存的資源總是發出新的請求呢?
- 4。對于緩存的內容,即使瀏覽器向服務器發送了請求,但服務器在接收到請求后,可能不會返回內容,而是讓瀏覽器繼續使用緩存的內容,這在實際應用中有什么好處呢?如何處理其具體細節呢?
- 5。服務器端也有緩存,當服務器接收到瀏覽器的請求后,假設它返回響應內容,但返回的響應內容可能不是最新的內容,而很可能是一個舊的緩存版本,這又是怎么回事呢?
- 瀏覽器緩存內幕與getLastModified方法
- 在HttpServlet類中定義了一個getLastModified方法,其完整語法定義如下:
- protected long getLastModified(HttpServletRequest req)
- 其中的返回值表示自1970年1月1日的0點0分0秒開始計算的一個毫秒數,HttpServlet類中定義的getLastModified方法總是返回一個負數,在HttpServlet子類中可以對這個方法進行覆蓋,以便返回一個代表當前輸出的響應內容的修改時間,HttpServlet類的service方法可以根據這個返回值在響應消息中自動生成Last-Modified頭字段。
- 一般情況下,瀏覽器都會緩存已經訪問過的頁面內容,getLastModified方法的返回值可以影響瀏覽器如何處理和利用緩存內容。在詳細了解getLastModified方法的應用之前,應該先對瀏覽器的緩存機制有所了解。
- 單擊IE瀏覽器的“工具“Internet選項”菜單,打開“Internet選項”對話框,接著再單擊“常規”選項卡中的“Internet臨時文件”欄中的“設置”按鈕,打開“設置”對話框。“設置”對話框的“Internet臨時文件夾”欄中,可以看到瀏覽器保存所有緩存頁面內容的文件夾的完整目錄名稱。
- “每次訪問此頁時檢查”選項表示瀏覽器每次訪問一個頁面時,不管瀏覽器是否緩存過此頁面,都要向服務器發出訪問請求。這種設置的優點是實時性很強,肯定能夠訪問到網頁的最新內容,但是如果網頁內容很少更新,這種設置的訪問效率就比較低了。
- “每次啟動Internet Explorer時檢查”選項表示在瀏覽器的每次啟動運行期間,在第一次訪問一個頁面時,不管瀏覽器是否緩存過此頁面,都要向服務器發出訪問請求,但是在瀏覽器的本次啟動運行期間對該頁面的后續訪問,瀏覽器將不再向服務器發出訪問請求,而是直接使用緩存中的內容。這種設置具有較高的訪問效率,同時也兼顧了較好的實時性,它可以保證每次啟動瀏覽器后看到的都是最新的網頁內容。
- “自動”選項與“每次啟動Internet Explorer時檢查”選項的功能相似,只是對圖像的訪問有所不同,如果隨著時間的推移,瀏覽器發現網頁上的圖像更新并不頻繁,這樣,即使瀏覽器在對某個已緩存的圖像執行本次啟動運行以來的第一次訪問時,它也不一定會向服務器發出訪問請求,而是干脆直接使用緩存中的內容。“自動”選項是瀏覽器的默認設置,所以,幾乎所有人的瀏覽器都是按照這種方式工作的,這個選項的作用和意義應該成為讀者熟悉的重點。
- “不檢查”選項表示瀏覽器不管在什么情況下訪問一個頁面時,只要能夠在本地找到此頁面的緩存信息,瀏覽器就不會向服務器發出訪問請求,而是直接使用緩存的內容。這種設置的優點是訪問效率很高,但是如果服務器端的網頁內容更新后,瀏覽器看到的內容很可能是過期的內容。
- 在瀏覽器的“檢查所存網頁的較新版本”的功能項采用默認的“自動”設置項的情況下,如果瀏覽器剛剛訪問過一個網頁,服務器端就更新了這個網頁的內容,當瀏覽在關閉前又重新訪問這個頁面時,用戶看到的將不是更新的網頁內容,而是過期的網頁內容。為了提高瀏覽效率,在訪問靜態的網頁內容時,這么一點小概率的過期信息還是應該允許的,并且這些過期信息也不會造成什么不好的后果,就像你偶爾有一次看到了前一天發生的新聞,而不是當天的新聞,這又有什么問題呢?可是,如果瀏覽器訪問的是一個動態網頁,這本來就要求瀏覽器在其整個運行期間的每次訪問都能看到最新的內容,例如,銷售一件商品后再回到商品庫存的顯示頁面時,看到的就應該是更新的庫存數據,而不應該是先前看到的內容。僅僅根據被訪問頁面的資源名稱,瀏覽器是無法知道商品庫存的顯示頁面是屬于動態內容,還是屬于靜態內容。對于這種情況,瀏覽器將根據響應消息中是否包含Last-Modified頭字段來進行處理,如果響應消息中沒有包含Last- Modified頭字段,它將在每次訪問此頁面時都向服務器發出訪問請求,否則,它僅在每次啟動運行后的第一次訪問此頁面時才向服務器發出訪問請求,而在啟動運行期間對此頁面的后續訪問都不再向服務器發出訪問請求。
- 響應消息中的Last-Modified頭字段可用于指定響應內容的最后更新時間,當客戶機緩存此文檔內容后,它在以后的請求消息中將根據 Last-Modified頭字段指定的時間來生成If-Modified-Since請求頭字段,以指出緩存文檔的最后更新時間。只有文檔的修改時間比 If-Modified-Since請求頭指定的時間新時,服務器才會返回文檔內容。如果自從If-Modified-Since指定的時間以來,網頁內容沒有發生修改,服務器將返回一個304(Not Modified)狀態碼來表示瀏覽器緩存的版本是最新的,而不會向瀏覽器返回文檔內容,瀏覽器則繼續使用以前緩存的內容。通過這種方式,可以在一定程度上減少瀏覽器與服務器之間的通信數據量,從而提高了通信效率。
- HttpServlet類為If-Modified-Since請求頭和Last-Modified頭字段的這種應用提供了處理機制,當繼承了 HttpServlet類的Servlet程序接收到一個GET方式的訪問請求時,HttpServlet中重載的service方法在調用doGet方法之前,它還將調用getLastModified方法,并根據getLastModified方法的返回值來決定是否調用doGet方法和在響應消息中是否生成Last-Modified頭字段,具體規則如下:
- 當getLastModified方法返回一個負數時,不管請求消息中的情況怎樣,service方法都將直接調用doGet方法來生成響應內容,這正是HTTPServlet類中定義的getLastModified方法的行為;
- 當getLastModified方法返回一個正數,且請求消息中沒有包含If-Modified-Since請求頭時(這往往出現在第對某個資源的第一次訪問時),或者請求消息中包含的If-Modified-Since請求頭中的時間值比getLastModified方法返回的時間值舊時,service方法將根據getLastModified方法的返回值生成一個Last-Modified頭字段,然后調用doGet方法生成響應內容;
- 當getLastModified方法返回一個正數時,且請求消息中包含的If-Modified-Since請求頭中的時間值比 getLastModified方法返回的時間值新或者與之相同時,service方法將不調用doGet方法,而是向瀏覽器返回一個304(Not Modified)狀態碼表示瀏覽器可以使用其以前緩存的內容。
===================================================================================================
使用Filter配置禁止緩存功能
Java代碼
NoCacheFilter.class
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class NoCacheFilter implements Filter {
public void destroy() {
}
//瀏覽器不緩存頁面
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException{
//設置禁止緩存的消息頭
((HttpServletResponse)response).setHeader("Pragma","No-cache");
((HttpServletResponse)response).setHeader("Cache-Control","no-cache");
((HttpServletResponse)response).setHeader("Expires","0");//禁止緩存
chain.doFilter(request, response);
System.out.print("NoCacheFilter");
}
public void init(FilterConfig arg0) throws ServletException {
}
}web.xml配置
NoCacheFilter.class
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class NoCacheFilter implements Filter {
public void destroy() {
}
//瀏覽器不緩存頁面
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException{
//設置禁止緩存的消息頭
((HttpServletResponse)response).setHeader("Pragma","No-cache");
((HttpServletResponse)response).setHeader("Cache-Control","no-cache");
((HttpServletResponse)response).setHeader("Expires","0");//禁止緩存
chain.doFilter(request, response);
System.out.print("NoCacheFilter");
}
public void init(FilterConfig arg0) throws ServletException {
}
}
<filter>
<filter-name>NoCacheFilter</filter-name>
<filter-class>com.huadi.tools.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<filter-class>com.huadi.tools.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>