說在開頭 javascript
《高性能建站指南》看了不少遍,一直沒有搞清楚緩存這一塊。。什麼expired,last-modified,eTag等等,本身只是知道,並無深刻了解,在http請求中,這些字段是如何判斷是否須要從服務端從新拿文件仍是利用緩存。看到了一篇不錯的文章,分享一下。 css
正文 html
每次訪問網頁,一般瀏覽器會從服務器下載所需的資源,例如 HTML 文檔、圖片、CSS、JavaScript,甚至包括字體文件等。這裏面的許多文件(例如圖片)都是不多變更的,若是每次都要從服務器從新下載,會沒必要要地增長網頁載入時間,同時也會對服務器形成必定壓力。經過合理配置緩存策略,可令瀏覽器以某種方式把這些靜態的文件緩存起來,下次請求同一資源時,直接使用本地存儲的副本,而不是從服務器從新下載。
java
啓用緩存至少有兩點顯而易見的好處:web
減小頁面加載時間正則表達式
減小服務器負載apache
瀏覽器是否使用緩存、緩存多久,是由服務器控制的。準確來講,當瀏覽器請求一個網頁(或者其餘資源)時,服務器發回的響應的「響應頭」部分的某些字段指明瞭有關緩存的關鍵信息。瀏覽器
Cache-Control緩存
Cache-ControlHTTP 響應頭是 HTTP 1.1 協議新增的指令,每一個資源均可以經過設定 Cache-Control 來創建緩存策略。一般,可爲它指定一個max-age,表示緩存的最長時間,單位爲秒。例如,若設定Cache-Control: max-age=604800,則表示這個資源的有效時間爲 7 天。瀏覽器第一次獲取這個資源後,7 天以內若再次請求,一般都不會與服務器進行任何通訊,而是直接使用本地副本。安全
此外,還能夠爲 Cache-Control 指定public或private標記。若是使用 private,則表示該資源僅僅屬於發出請求的最終用戶,這將禁止中間服務器(如代理服務器)緩存此類資源。對於包含用戶我的信息的文件(如一個包含用戶名的 HTML 文檔),能夠設置 private,一方面因爲這些緩存對其餘用戶來講沒有任何意義,另外一方面用戶可能不但願相關文件儲存在不受信任的服務器上。須要指出的是,private 並不會使得緩存更加安全,它一樣會傳給中間服務器(若是網站對於傳輸的安全性要求很高,應該使用傳輸層安全措施)。對於 public,則容許全部服務器緩存該資源。一般狀況下,對於全部人均可以訪問的資源(例如網站的 logo、圖片、腳本等),Cache-Control 設爲 public 是合理的。
Expires
一樣是用來控制緩存,Expires響應頭從另外一個角度——指明緩存的具體過時日期,來控制資源什麼時候過時。在過時時間之內,若再次發起請求,一般瀏覽器都不會與服務器進行任何通訊,而是直接使用本地副本。Apache 服務器容許以多種方式,例如基於該資源的訪問時間或上次修改時間來設定 Expires 的值。注意,這裏的時間一概使用格林威治時間(Greenwich Mean Time, GMT),而非本地時間。
當 Expires 和 Cache-Control 同時出現時,一般後者會覆蓋前者的設定。因爲 Expires 對用戶的系統時間有所依賴,所以一般認爲使用 Cache-Control 是更好的選擇(基本上全部的瀏覽器都支持 Cache-Control 指令)。
Last-Modified 和 ETag
服務器可在 HTTP 返回頭中包含Last-Modified字段或者ETag字段。Last-Modified 表示被請求資源在服務器端的上次修改時間,而 ETag 則是一個惟一文件標識符,每次文件修改後都會生成一個新的 ETag。服務器經過向瀏覽器發送這兩個字段,來告知瀏覽器其得到的資源的版本。
不管經過 Cache-Control 仍是 Expires 設置緩存,在過時時間之內,當用戶點擊瀏覽器刷新按鈕時,爲了確保用戶所加載的資源是最新的,大部分瀏覽器不會再直接使用緩存中的數據,而是發出一個條件請求(Conditional GET Request)。對於這類請求,瀏覽器會在請求頭中包含If-Modified-Since或If-None-Match字段。前者即瀏覽器當初獲得的 Last-Modified;後者即瀏覽器當初獲得的 ETag。當服務器發現資源的更新時間晚於 If-Modified-Since 所提供的時間,或者資源在服務器端當前的 ETag 和 If-None-Match 提供的不符時,會響應整個資源,不然只會響應一個 304 Not Modified 狀態碼(所以瀏覽器將不須要從新下載整個資源)。這種機制能夠最大程度上減小數據下載量。此外,若是緩存的資源已過時,瀏覽器一般有兩種選擇:從新下載這個資源,或發出一個條件請求。不少瀏覽器都會採起後者,以節約資源。
因爲 Last-Modified 和 ETag 的做用是相同的(均爲向服務器驗證資源是否最新),所以只使用一個便可。一般認爲 Last-Modified 更好(它和 Expires 不一樣,由服務器生成,不依賴瀏覽器端時間)。
個人網站啓用緩存了嗎?
用瀏覽器的開發者工具或插件查看
爲了肯定是否啓用了緩存,只須要檢查服務器發回的「響應頭」就能夠。許多瀏覽器以及工具均可以檢查這些信息,咱們以 Firefox 的插件 Firebug 爲例。如圖所示:
沒有包含Cache-Control以及Expires信息。
在線檢測
也有一些方便的在線檢測服務,用於對網站速度給出建議,其中就會檢測緩存設置狀況。好比 Yahoo! 公司的 YSlow,以及百度站長工具等,都有相應的功能。你們能夠去百度那裏檢測一下,目前是不須要登陸便可檢測的。
使用緩存的策略
爲靜態資源設置長緩存時間
有些資源是很長時間不會改變的,好比網站的 logo 圖片、jQuery 庫、字體等,所以能夠爲它們設定「永不過時」的緩存時間,例如設定爲 10 年。
確保文件修改生效
有些時候咱們會修改一些資源,好比更新了 jQuery 版本,或網站的 CSS 樣式。若是這些資源已經被緩存,那麼除非用戶手工刷新頁面,不然要等緩存天然過時以後用戶纔會得到新版本。如何在這種狀況下強制瀏覽器從新下載呢?最有效的一個辦法就是在這類資源的文件名中包含版本信息,並在更改以後對應地修改文件名。瀏覽器發現文件更換後,天然沒法使用緩存,而會從新下載。
對於 HTML 文檔謹慎設定過時時間
大部分狀況下,對於其餘圖片、CSS、JavaScript 等資源的請求都來自一個單一的 HTML 文檔。對於這類頁面一般應該設定比較短的過時時間,或者乾脆不設定。由於若是這類頁面被緩存,那麼頁面中包含的資源的文件名等等信息都會一併被緩存,致使對它的更新難以確保當即對用戶生效。
引用靜態資源時,不要使用 Query String
Query String 就是例如?key=val的字符串,如
<script src="/static/js/func.js?v=a87ff8"></script>
這會阻止一部分較老的瀏覽器(包括 IE6 )對該資源進行緩存。
設定緩存的方法
對於 Apache 服務器,能夠經過 mod_expires 模塊來設定ExpiresHTTP 頭或Cache-ControlHTTP 頭的max-age指令。編輯相應目錄下的 .htaccess 文件,或直接對 Apache 的配置文件(根據服務器系統版本不一樣,可能爲httpd.conf或apache2.conf等)做出修改。
分文件類別設定
使用ExpiresByType能夠按照文件的 MIME Type 設定某一類文件的過時日期。例如:
<IfModule mod_expires.c> ExpiresActive On ExpiresByType text/css "access plus 1 week" ExpiresByType application/javascript "access plus 2 weeks" ExpiresByType p_w_picpath/x-icon "access plus 6 months" ExpiresByType p_w_picpath/gif "access plus 6 months" ExpiresByType p_w_picpath/png "access plus 6 months" ExpiresByType p_w_picpath/jpeg "access plus 6 months" ExpiresByType video/x-flv "access plus 6 months" ExpiresByType application/pdf "access plus 6 months" </IfModule>
其中access plus 1 week表示將緩存過時設置爲訪問時間(即當前時間)以後的一週。若是將access替換爲modification,則緩存過時會被設定爲文件修改時間以後的一週。可使用的時間單位包括:
years months weeks days hours minutes seconds
不一樣的時間也能夠進行組合,例如:
ExpiresByType text/html "access plus 1 month 15 days 2 hours" ExpiresByType p_w_picpath/gif "modification plus 5 hours 3 minutes"
根據文件擴展名進行設置
若是但願根據擴展名來指定緩存規則,可使用FilesMatch配合正則表達式。爲了簡潔,我這裏只規定了ExpiresDefault。它的優先級很低,只會在對應文件沒有任何其餘規則可以匹配(包括上層目錄下的緩存規則)時生效。
<IfModule mod_expires.c> <FilesMatch "\.(css|js)$"> ExpiresActive on ExpiresDefault "access plus 1 week" </FilesMatch> </IfModule>
對某些文件設定
同理,也能夠對某些文件啓用特定的緩存策略。注意,文件名中的點(.)是須要轉義的。
<IfModule mod_expires.c> <FilesMatch "^(example\.css|example\.js)$"> ExpiresActive on ExpiresDefault "access plus 1 week" </FilesMatch> </IfModule>
對某一文件夾下的全部文件設定
對於靜態文件,一個比較方便的作法是將它們所有放到一個目錄下,並對該目錄下的全部文件設定。可是,此處須要注意防止其餘規則將ExpiresDefault覆蓋掉。
<IfModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 10 years" </IfModule>
有用的工具及參考資料
Cache-Control header checker(可檢測給定的地址是否啓用了 Cache-Control,還會教你如何設定)
Caching Tutorial for Web Authors and Webmasters