HTTP If-Modified-Since引發的瀏覽器緩存匯總


在看Spring中HttpServlet的Service方法時,對於GET請求,代碼邏輯如下:

if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        }

其中涉及的關鍵信息是修改時間,這就涉及到瀏覽器數據緩存問題。以下對個緩存機制進行簡單總結,可用於請求的優化。(本文中的圖都摘自其他文章

Last-Modified和If-Modified-Since

當瀏覽器GET請求的時候,如果有If-Modified-Since,則會與當前服務器上相關資源最后一次修改時間進行對比,如果相同則返回304(資源可訪問,但沒修改),否則加載最新數據,瀏覽器再緩存起來。這樣減少網絡數據傳輸和服務器壓力。

ETags和If-None-Match

根據修改時間判斷文件是否被修改,如果一個網頁被頻繁更新,但實際內容並沒有更新,依然會對服務器造成壓力。引入了ETags和If-None-Match,其不同於Last-Modified和If-Modified-Since取決於修改時間,可以依賴其他屬性,如資源的MD5等。當資源被更新,但實際內容沒有更新,則會比較修改時間和ETags,如果ETags沒變,則不更新數據資源。但查閱源碼戴發現,目前底層實現上實現的是弱Etags,其由文本長度和修改時間組成,資源被更新后,ETags依然會更新。在AbstractResource中,代碼如下:

  @Override
    public final String getETag() {
        if (weakETag == null) {
            synchronized (this) {
                if (weakETag == null) {
                    long contentLength = getContentLength();
                    long lastModified = getLastModified();
                    if ((contentLength >= 0) || (lastModified >= 0)) {
                        weakETag = "W/\"" + contentLength + "-" +
                                   lastModified + "\"";
                    }
                }
            }
        }
        return weakETag;
    }

 

Expires

添加Expires頭能有效的利用瀏覽器的緩存能力來改善頁面的性能,能在后續的頁面中有效避免很多不必要的Http請求,WEB服務器使用Expires頭來告訴Web客戶端它可以使用一個組件的當前副本,直到指定的時間為止。例如:Expires:Thu,15 Apr  2010  20:00:00  GMT;  他告訴瀏覽器緩存有效性持續到2010年4月15日為止,在這個時間之內相同的請求使用緩存,這個時間之外使用http請求。Expires有一個非常大的缺陷,它使用一個固定的時間,要求服務器與客戶端的時鍾保持嚴格的同步,並且這一天到來后,服務器還得重新設定新的時間。

Cache-Control

HTTP1.1引入了Cathe-Control,它使用max-age指定組件被緩存多久(時間相對請求的時間),從請求開始在max-age時間內瀏覽器使用緩存,之外的使用請求,這樣就可以消除Expires的限制。但有個缺點就是,用戶不能第一時間拿到最新修改的文件。請求過程如下:

 

另外,gulp 給靜態資源文件添加hash(md5)后綴防止緩存無效,能獲取最新文件(這個需要進一步研究)

參考:

HTTP的請求頭標簽 If-Modified-Since 

If-Modified-Since和If-None-Match

http://www.360doc.com/content/17/0721/17/41344223_673116604.shtml 

前端性能優化 —— 添加Expires頭

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM