概述
為了減少服務器帶寬的需求,我們要減少客戶端與服務器端交互的數據量。解決方法如下:
1. 緩存很少變化的靜態資源,比如JS,CSS和圖片。
2. 對網絡交互的數據進行壓縮,比如對JS,CSS,HTML,圖片等。
3. 減少客戶端與服務器端的交互次數,我們可以合並所有的JS文件,合並所有的CSS文件。
本文主要討論靜態資源的緩存,其余部分請參考其他文章。
緩存位於服務器之間和客戶端之間,根據請求保存輸出內容的副本,如html頁面,圖片,文件,當下一個請求來到時,如果相同的URL,直接使用副本響應訪問請求,而不向源服務器再次發送請求。
緩存的類型
1. 瀏覽器緩存
瀏覽器都有關於緩存的設置(參考:http://www.cnblogs.com/ivanfu/archive/2012/04/26/2471103.html),通過在電腦硬盤存儲已經看過的網站的副本。
2. 代理服務器緩存
Web代理服務器使用同樣的緩存原理,代理服務器群為成百上千用戶服務使用同樣的機制;代理服務器緩存是共享緩存,為大量用戶使用,因此在減少相應時間和帶寬使用方面很有效,同一個副本會被重用多次。
3. 網關緩存
也稱為反向代理緩存或間接代理緩存,網關緩存也是一個中間服務器,和內網管理員部署緩存用於節省帶寬不同,網關緩存一般是網站管理員自己部署,讓他們的網站更容易擴展並獲得更好的性能。請求有幾種方法被路由到網關緩存服務器上,其中典型的是讓用一台或多台負載均衡服務器從客戶端看上去是源服務器。網絡內容發布商 (Content delivery networks CDNs)分布網關緩存到互聯網上,並出售緩存服務給需要的網站。
緩存如何工作
1. 如果響應頭信息:告訴緩存器不要保留緩存,緩存器就不會緩存相應內容。
2. 如果請求信息是需要認證或者安全加密的,相應內容默認不會被緩存。
3. 如果在回應中不存在校驗器(ETag或者Last-Modified頭信息),緩存服務器會認為缺乏直接的更新度信息,內容將會被認為不可緩存。
4. 一個緩存的副本如果含有以下信息,內容將會被認為是足夠新的
- 含有完整的過期時間和壽命控制頭信息,並且內容仍在保鮮期內。
- 瀏覽器已經使用過緩存副本,並且在一個會話中已經檢查過內容的新鮮度。
- 緩存代理服務器近期內已經使用過緩存副本,並且內容的最后更新時間在上次使用期之前。
5. 如果緩存的副本已經太舊了,緩存服務器將向源服務器發出請求校驗請求,用於確定是否可以繼續使用當前拷貝繼續服務。
五種常用於控制客戶端緩存的頭標
1. Last-Modified 最后修改時間
這 個頭標是一個響應頭標,表示客戶端(通常指瀏覽器)所請求資源在服務器端的最后修改時間,通常情況下客戶端在接受這個頭標后,在以后對這個資源的請求會附 帶一個’If-Modified-Since’請求頭標,而這個頭標是想告訴服務器上次客戶端所請求資源的最后修改時間,對於一些圖像,css,js等靜 態文件資源,配置好了的apache服務器會理解這些If-Modified-Since請求頭標,將頭標里的時間和文件的最后修改時間進行比較並作出響 應,如果二者相等則發送一個304 Not Modfied來告訴客戶端所請求資源並未修改讓客戶端放心使用緩存中的資源,否則的話會重新發送一個新的資源和新的Last-Modified的頭標。 但是對於一個動態的PHP腳本,我們即使在腳本加入了header(‘Last Modified: ‘.$time)來發送一個Last Modified響應頭標,當客戶端附帶’If-Modified-Since’在次請求時apache服務器不會進行處理,這需要我們自己 用$_SERVER['HTTP_IF_MODIFIED_SINCE']來獲取’If-Modified-Since’的值自己來進行判斷處理。
2. ETag(Entity Tag) 實體標簽
和Last-Modified類似,也是WEB服務器和客戶端用於確認緩存組件的有效性的一種機制,apache 1.3和2.0的ETag格式是inode-size-timestamp,因此當資源被修改,其ETag也發生改變,ETag相對Last- Modified更精確,Last-Modified只能精確的s級別,但是ETag在多服務器可能造成混亂,所以用還是不用還得看實際情況,其相對應的 后續請求頭標為If-None-Match。
3. Expires 過期時間
這個屬性告訴緩存器相關副本在多長時間內是新鮮的。過了這個時間,緩存器就會向源服務器發送請求,檢查文檔是否被修改。幾乎所有的緩存服務器都支持Expires屬性。可以設計一個絕對時間間隔:基於客戶最后查看副本的時間(最后訪問時間)或者根據服務器上文檔最后被修改的時間。Expires頭信息對於設置靜態圖片緩存特別有用,這些圖片修改很少,可以給它們設置一個特別長的過期時間,這會使網站對用戶變得相應非常快。
4. Pragma 編譯指示
HTTP頭信息中Pragma: no-cache 並不一定會讓內容無法被緩存,HTTP的規范中,響應型頭信息沒有任何關於Pragma屬性的說明,而討論了的是請求型頭信息 Pragma屬性,集中緩存服務器大部分不會用這個參數。
5. Cache-Control 緩存控制
讓網站的發布者控制他們的內容,並定位過期時間的限制。比如:Cache-Control: max-age=3600, public,可選項如下:
- max-age =[秒] 執行緩存的最長時間,[秒]是一個數字,單位是秒:從請求時間開始到過期時間之間的秒數。
- s-maxage =[秒] 類似於max-age屬性,除了他應用於共享(如:代理服務器)緩存
- public 標記認證內容也可以被緩存,一般來說: 經過HTTP認證才能訪問的內容,輸出是自動不可以緩存的;
- no-cache 強制每次請求直接發送給源服務器,而不經過本地緩存版本的校驗。這對於需要確認認證應用很有用(可以和public結合使用),或者嚴格要求使用最新數據的應用(不惜犧牲使用緩存的所有好處);
- no-store 強制緩存在任何情況下都不要保留任何副本
- must-revalidate 告訴緩存必須遵循所有你給予副本的新鮮度的,HTTP允許緩存在某些特定情況下返回過期數據,指定了這個屬性,高速緩存,希望嚴格的遵循你的規則。
- proxy-revalidate 和 must-revalidate類似,除了他只對緩存代理服務器起作用
如何寫利於緩存的代碼
1. 保持URL穩定,這是緩存的金科玉律,如果在不同的頁面上,給不同用戶或者從不同的站點上提供相同的內容,應該使用相同的URL,這使網站緩存友好簡單,最高效。
2. 盡量避免使用POST,POST模式的返回內容不會被大部分緩存服務器保存,如果你發送內容通過URL和查詢(通過GET模式)的內容可以緩存下來供以后使用。
3. 生成並返回Content-Length頭信息。這個屬性讓你的腳本在可持續鏈接模式時,客戶端可以通過一個TCP/IP鏈接同時請求多個副本,而不是為每次請求單獨建立鏈接,這樣你的網站相應會快很多。
4. 對於定期更新的內容設置一個緩存服務器可識別的max-age屬性或過期時間。對於不經常改變的圖片/頁面啟用緩存 ,並使用Cache-Control: max-age屬性設置一個較長的過期時間。