nginx 簡單實踐:Web 緩存【nginx 實踐系列之三】
〇、前言
本文為 nginx 簡單實踐系列文章之一,主要簡單實踐了:web 緩存,僅供參考。
關于 Nginx 基礎,以及安裝和配置詳解,可以參考博主過往文章:
http://www.rzrgm.cn/hnzhengfy/p/Nginx.html
一、強制緩存、協商緩存
1.1 強制緩存(強緩存)
強制緩存指的是當用戶請求一個資源時,瀏覽器直接從本地緩存中讀取數據而不向服務器發(fā)送任何請求。
這種緩存機制主要依賴于 HTTP 響應頭中的 Cache-Control 和 Expires 字段。
Expires:這是 HTTP/1.0 引入的一個頭部字段,它指定了資源在該時間之前被認為是有效的。例如,Expires: Wed, 21 Oct 2025 07:28:00 GMT。但是,由于 Expires 依賴于客戶端的時間設置,可能出現非預期的狀況。
Cache-Control:HTTP/1.1 引入了更為強大的 Cache-Control 頭部,提供了更多控制緩存行為的指令,如下表:
| 值 | 含義 |
| no-store | 禁止緩存(強緩存和協商緩存),客戶端不存儲任何值 |
| no-cache | 禁止強緩存,需要重寫驗證(可以理解為禁止強緩存,啟用協商緩存) |
| private | 私有緩存,禁止中間人(比如 CDN 等代理緩存) |
| public | 共享緩存,允許中間人緩存 |
| max-age | 資源可以被緩存的最大時間,單位:秒,是一個相對時間,優(yōu)先級高于 Expires,示例(緩存兩分鐘):max-age=120 |
| s-maxage | 用于共享緩存,單位:秒,如果在其有效期內,不去訪問 CDN 等。s-maxage 會覆蓋 max-age 和 Expires |
| must-revalidate | 緩存使用陳舊資源時,必需先驗證狀態(tài) |
強緩存的優(yōu)勢:
- 減少網絡請求:瀏覽器可以直接使用本地緩存中的資源,無需再次向服務器發(fā)起請求,從而減少了網絡往返次數,提升了頁面加載速度。
- 降低服務器負載:由于減少了對服務器的請求,服務器的壓力也隨之減小,有助于提高服務器的整體性能和穩(wěn)定性。
- 節(jié)省帶寬:避免了重復下載相同的數據,節(jié)省了用戶的網絡帶寬,尤其對于移動設備或在帶寬有限的情況下尤為重要。
- 提升用戶體驗:加速頁面加載時間,尤其是對于靜態(tài)資源如圖片、CSS 和 JavaScript 文件等,能夠顯著改善用戶體驗。
強緩存的劣勢:
- 可能展示過期內容:如果緩存策略設置不當,可能會導致用戶看到過期的內容。例如,如果資源更新了但緩存尚未過期,用戶將繼續(xù)看到舊版本的資源,直到緩存失效。
- 缺乏靈活性:強制緩存的時間是預先設定好的,無法根據實際情況動態(tài)調整。這意味著即使服務器上的資源已經更新,只要客戶端緩存未過期,用戶就看不到最新的內容。
- 需要精確配置:正確配置緩存策略需要一定的專業(yè)知識,尤其是在處理不同類型的資源時(如靜態(tài)資源與動態(tài)生成的內容),錯誤的配置可能導致緩存命中率低或頻繁的緩存失效問題。
- 難以應對緊急更新:在某些情況下,比如發(fā)現安全漏洞或需要立即推送的重要更新,強制緩存可能會成為障礙,因為用戶可能長時間看不到最新的修復或更新。
在實際應用中,通常會結合使用強制緩存和協商緩存,以達到既快速又可靠的緩存效果。例如,對于不經常變化的靜態(tài)資源可以使用較長的緩存時間,而對于可能頻繁更新的內容則采用較短的緩存時間或者使用協商緩存機制。
1.2 協商緩存
協商緩存(也稱為驗證緩存)是一種 HTTP 緩存機制,它在強制緩存失效后使用。
在這種情況下,瀏覽器會攜帶特定的緩存標識(如 ETag 或 Last-Modified)向服務器發(fā)送請求,詢問資源是否有更新。如果資源沒有變化,服務器將返回一個 304 Not Modified 狀態(tài)碼,指示客戶端可以繼續(xù)使用本地緩存;如果資源有變化,則服務器返回新的資源。


協商緩存主要依賴于 值標記法(ETag、If-None-Match)和比較最后修改時間法(Last-Modified、If-Modified-Since)兩種頭部字段來實現。
值標記法(ETag、If-None-Match):
- ETag:由服務器生成并返回給客戶端的一個唯一標識符,通常基于文件內容的哈希值。每當資源發(fā)生變化時,ETag 也會隨之改變。
- If-None-Match:當客戶端再次請求資源時,會在請求頭中帶上之前獲取的 ETag 值。服務器收到請求后,會比較當前資源的 ETag 與請求中的 If-None-Match 值。如果兩者相同,說明資源未變,服務器返回 304 Not Modified(未更改,緩存可用);否則,服務器返回新的資源及其新的 ETag。
比較最后修改時間法(Last-Modified、If-Modified-Since):
- Last-Modified:服務器告訴客戶端資源最后修改的時間。例如,Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT。
- If-Modified-Since:客戶端在后續(xù)請求中會帶上這個時間戳。服務器接收到請求后,檢查資源的最后修改時間 Last-Modified 是否晚于 If-Modified-Since 指定的時間。如果是,服務器返回新資源;如果不是,服務器返回 304 Not Modified(未更改,緩存可用)。
協商緩存的優(yōu)勢:
- 確保數據新鮮度:通過與服務器進行驗證,確保用戶始終能夠獲取到最新的資源,避免了因緩存過期而看不到最新內容的問題。
- 節(jié)省帶寬:如果資源沒有變化,服務器只需返回一個小的 304 Not Modified 響應,而不需要重新傳輸整個資源,從而節(jié)省了帶寬。
- 靈活性:相比強制緩存,協商緩存提供了更高的靈活性,允許根據實際資源的變化情況動態(tài)調整緩存策略。
協商緩存的劣勢:
- 增加網絡開銷:即使資源沒有變化,每次請求都需要與服務器進行一次驗證,這增加了少量的網絡開銷。
- 復雜性較高:需要正確設置和管理 ETag、Last-Modified 等頭部字段,增加了配置和維護的復雜性。
- 性能略遜于強緩存:雖然節(jié)省了帶寬,但相比直接從緩存中讀取資源,協商緩存仍需要一次網絡往返,因此性能稍遜一籌。
通過合理地結合使用強制緩存和協商緩存,可以根據不同的需求優(yōu)化網站的性能和用戶體驗。
對于不常變化的靜態(tài)資源,可以優(yōu)先考慮使用強制緩存;而對于那些需要保持最新狀態(tài)的資源,則應采用協商緩存。
二、通過 nginx 配置實現 Web 緩存
2.1 強緩存的實現:Cache-Control
Expires 可能造成誤差,因此不再進行示例測試。由于 Expires 配置是后端返回給客戶端的一個時間戳,取自服務器時間,當客戶端發(fā)送請求時,采用客戶端的當前時間進行比較,如果兩邊時間有誤差就會造成數據不一致的異常情況。
Cache-Control 的優(yōu)先級高于 Expires,Expires 是 http1.0 的產物,而 Cache-Control 是 http1.1 的產物,兩者同時存在的時候 Expire 會被 Cache-Control 的 max-age 覆蓋,在不支持 http1.1 的情況下可能就需要 Expires 來保持兼容。
nginx 配置示例:
server {
listen 8888;
server_name www.testczzj.com;
#charset utf-8;
#charset koi8-r;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
add_header Cache-Control max-age=500; # 緩存有效期配置為 500 秒
proxy_pass http://www.testczzj.com:5000;
}
}
如下圖請求結果:(響應頭中包含了強緩存配置項 Cache-Control)

如下圖針對文件 bootstrap.min.css 的二次請求詳情:

2.2 協商緩存實現:Cache-Control:no-cache
客戶端每次請求都會向服務端發(fā)起,若沒更新則返回 304,若有更新就正常返回 200。
nginx 配置,其實就是修改了 Cache-Control 這個配置項:
server {
listen 8888;
server_name www.testczzj.com;
#charset utf-8;
#charset koi8-r;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
add_header Cache-Control no-cache; # 配置為協商緩存
proxy_pass http://www.testczzj.com:5000;
}
}
如下圖,首次加載是從服務器拉取全部數據,待第二次刷新時,在服務端數據未發(fā)生變更的情況下,返回 304,效率大大提高:

如下圖針對文件 bootstrap.min.css 的二次請求詳情:

2.3 無緩存:Cache-Control:no-store
nginx 配置如下:
server {
listen 8888;
server_name www.testczzj.com;
#charset utf-8;
#charset koi8-r;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
add_header Cache-Control no-store; # 配置無緩存
proxy_pass http://www.testczzj.com:5000;
}
}
每次請求都是從服務端取數據,如下圖:

參考:https://blog.csdn.net/JarryNeverGiveup/article/details/131060939
本文來自博客園,作者:橙子家,歡迎微信掃碼關注博主【橙子家czzj】,有任何疑問歡迎溝通,共同成長!

浙公網安備 33010602011771號