要將緩存存到客戶端瀏覽器,關鍵是讓 瀏覽器接收到合適的 HTTP 緩存控制響應頭。這通常通過 add_header
添加控制頭來實現。
? 一般做法(強緩存 + 協商緩存):
🔹 1. 強緩存:使用 Cache-Control
和 Expires
location /static/ {root /path/to/static/files;add_header Cache-Control "max-age=3600, public";add_header Expires $http_expires;
}
max-age=3600
:緩存 3600 秒public
:任何緩存服務器或瀏覽器都可以緩存Expires
:指定絕對過期時間(可選)
🔹 2. 協商緩存:使用 ETag
和 Last-Modified
如果你在服務靜態資源,比如:
location /static/ {root /path/to/static/files;etag on;if_modified_since exact;add_header Cache-Control "no-cache";
}
- 瀏覽器下次訪問時會帶
If-None-Match
或If-Modified-Since
,服務器可返回304 Not Modified
🧠 如果你是用 OpenResty 返回的 Lua 內容:
你可以手動添加緩存相關頭部,例如:
ngx.header["Cache-Control"] = "max-age=60, public"
ngx.header["Expires"] = ngx.http_time(ngx.time() + 60)
ngx.say("hello world")
這樣瀏覽器會在 60 秒內使用本地緩存,不會再請求服務端。
🧪 如何驗證瀏覽器緩存是否生效?
方法一:Chrome F12 → Network → 觀察響應頭
-
狀態碼 200 + from memory cache 或 disk cache
-
狀態碼 304 表示協商緩存命中
-
響應頭中應有:
Cache-Control
Expires
ETag
/Last-Modified
(如開啟)
? 實戰建議
靜態資源使用強緩存:
location /assets/ {root /usr/share/nginx/html;add_header Cache-Control "max-age=31536000, public";
}
動態接口用協商緩存或短時間強緩存(配合版本號或參數):
location /api/data {content_by_lua_block {ngx.header["Cache-Control"] = "max-age=10"ngx.say("data at ", ngx.now())}
}
是不是看的云里霧里?我們來一步步詳細講解如何讓 OpenResty/Nginx 將數據緩存到瀏覽器端(客戶端),這樣客戶端再次訪問時就不必重復請求。
🎯 目標
讓瀏覽器緩存接口或靜態資源內容,避免每次都請求服務器,提高性能。
🧱 基礎概念先弄清楚
緩存類型 | 控制方式 | 瀏覽器行為 |
---|---|---|
強緩存 | Cache-Control + Expires | 瀏覽器 不發請求,直接用本地緩存 |
協商緩存 | ETag 或 Last-Modified | 瀏覽器 發請求,但服務器判斷內容未變,返回 304,無內容體 |
? 示例一:配置強緩存(適用于靜態資源)
location /static/ {root /Users/yourname/openresty-static; # 靜態文件目錄add_header Cache-Control "public, max-age=3600";add_header Expires $http_expires;
}
解釋:
max-age=3600
:緩存 3600 秒(1 小時)public
:允許任何緩存服務器(包括瀏覽器)緩存Expires
:兼容舊瀏覽器(用絕對時間)
🧪 測試方法:
- 瀏覽器訪問一次
/static/test.js
- 再刷新,看 Network →
test.js
狀態為200 from memory/disk cache
? 示例二:動態接口設置緩存頭(Lua 模擬)
location /api/time {content_by_lua_block {ngx.header["Cache-Control"] = "public, max-age=30"ngx.header["Expires"] = ngx.http_time(ngx.time() + 30)ngx.say("server time: ", ngx.now())}
}
解釋:
- 設置響應頭,告訴瀏覽器:30秒內請直接使用本地緩存
- 瀏覽器不會向服務器請求這段時間內的
/api/time
🧪 測試方法:
- 瀏覽器訪問
/api/time
,記錄時間 - 再訪問一次,響應不變、Network 顯示
from memory cache
,說明緩存生效
? 示例三:協商緩存(加上 ETag)
如果你服務靜態文件,可以這樣配置:
location /docs/ {root /Users/yourname/openresty-docs;etag on;if_modified_since exact;add_header Cache-Control "no-cache";
}
解釋:
etag on
: Nginx 生成 ETag(唯一標識當前內容版本)no-cache
: 瀏覽器每次請求都會帶If-None-Match
,服務器返回 304 表示內容沒變
🧪 測試方法:
- 第一次請求
/docs/intro.html
→ 返回 200 - 第二次請求瀏覽器自動帶上
If-None-Match
→ 返回 304 Not Modified
協商緩存(Conditional Requests)機制中,瀏覽器每次都會帶上 ETag
或 Last-Modified
發起請求,以詢問服務器是否資源有更新。
🔁 協商緩存工作機制(以 ETag
為例)
第一次請求:
-
瀏覽器訪問
/example.js
-
服務器響應:
200 OK ETag: "abc123" Cache-Control: no-cache
瀏覽器會把這個 ETag 存起來。
第二次請求(瀏覽器再次訪問):
-
瀏覽器自動帶上頭部:
If-None-Match: "abc123"
-
服務器比對資源的當前 ETag 與請求的
If-None-Match
:-
如果一樣 → 資源沒變,返回:
304 Not Modified
無內容體,瀏覽器用本地緩存展示。
-
如果不一樣 → 資源已變,返回新的 200 和更新的內容與 ETag。
-
📦 注意:
- 你必須顯式設置
Cache-Control: no-cache
,表示 “每次請求都要驗證” - 如果你不設置,默認不會發起協商請求,可能只靠
max-age
強緩存
🚧 注意事項
- 接口不宜長期緩存,可以短時間緩存如 5~60 秒,用于頻繁請求但數據變化不快的情況。
- 靜態資源可以長期緩存,但要結合文件名加 hash,如
main.abcd1234.js
- 如果你用 Vue/React 構建的頁面,也可以通過
nginx.conf
給/dist
設置緩存頭
📦 常見 Cache-Control 組合參考
場景 | 配置示例 | 說明 |
---|---|---|
瀏覽器強緩存 | Cache-Control: public, max-age=86400 | 一天內直接使用本地緩存 |
協商緩存 | Cache-Control: no-cache + ETag | 每次請求,服務器可返回304 |
不緩存 | Cache-Control: no-store | 瀏覽器不保存任何內容 |
CDN 緩存,瀏覽器不緩存 | Cache-Control: public, max-age=86400, must-revalidate | 瀏覽器每次都向服務器確認 |
題外話:
CDN 緩存(Content Delivery Network 緩存)是指將網站的靜態資源(如圖片、JS、CSS、HTML等)緩存在離用戶更近的邊緣節點服務器上,以提升訪問速度、減輕源站壓力、提升系統可用性。
🧠 一句話理解:
CDN 緩存就是:
“讓用戶訪問 CDN 邊緣節點的緩存副本,而不是每次都去請求源站”。
? 需要注意的是邊緣節點是 CDN 服務商提供的,不是你自己買的服務器。
🧠 什么是邊緣節點?
邊緣節點(Edge Node)是 CDN 服務商在全國各地、甚至全球布置的緩存服務器。這些服務器靠近用戶,稱為“邊緣”。
比如你用了阿里云 CDN,當上海的用戶訪問你的網站時,請求不會直接打到你自己的源站服務器,而是訪問阿里云在上海部署的 CDN 節點。
📦 誰提供這些邊緣節點?
你不需要自己買,常見 CDN 服務商都提供大量邊緣節點:
CDN 服務商 | 邊緣節點說明 |
---|---|
阿里云 CDN | 全國幾百個節點,支持全球覆蓋 |
騰訊云 CDN | 國內+海外分布式節點 |
百度云加速 | 全國部署節點 |
七牛云 CDN | 國內主打圖床/加速 |
Cloudflare | 全球超過 300+ 城市節點 |
AWS CloudFront | 全球 CDN 服務,適合國際化 |
Fastly / Akamai | 國際大廠,專注北美和全球 |
🖼? 舉個例子幫助你理解
你的網站部署在北京阿里云的一臺服務器上,用戶可能來自全國各地:
用戶地理位置 | 沒有 CDN | 有 CDN |
---|---|---|
北京 | 快(直連) | 更快(邊緣節點) |
廣州 | 慢(跨區訪問) | 快(廣州本地 CDN 節點) |
上海 | 慢(跨區) | 快(上海本地節點) |
美國 | 非常慢(跨境) | 快(洛杉磯/SF 節點) |
🛠? 如何使用這些邊緣節點?
-
你將資源部署在源站(比如你的服務器、對象存儲等)
-
你通過 CDN 服務商的加速域名對外訪問,比如:
原地址:https://yourserver.com/logo.png CDN 加速地址:https://cdn.yourdomain.com/logo.png
-
用戶訪問的是 CDN 域名,CDN 會自動在邊緣節點緩存和分發。
💡 總結一句話:
CDN 的邊緣節點是 CDN 平臺提供的,分布在各地,你無需部署也無需購買,只要開通使用即可享受加速服務。
🗂? 緩存的內容類型
CDN 常緩存以下內容:
資源類型 | 是否常緩存 |
---|---|
圖片(.jpg/.png/.gif) | ? |
JS/CSS/字體文件 | ? |
HTML 頁面(根據配置) | ?(需配置) |
接口數據(JSON 等) | ?(需配置) |
視頻/音頻資源 | ? |
🏗? CDN 緩存原理
-
用戶訪問資源(如
https://cdn.example.com/logo.png
) -
CDN 邊緣節點查找本地緩存:
- ? 找到了(命中緩存):直接返回。
- ? 沒有(未命中緩存):回源到源站,取回資源 → 緩存在邊緣節點 → 返回用戶。
-
下一次其他用戶訪問時就直接用緩存了。
🔐 緩存控制方式(CDN 依據這些控制)
CDN 判斷是否緩存/是否過期主要依賴:
響應頭 | 說明 |
---|---|
Cache-Control | 是否緩存、緩存多久(如 max-age=600 ) |
Expires | 指定過期時間(已被 Cache-Control 替代) |
ETag /Last-Modified | 協商緩存用,做回源時判斷是否更新 |
Vary | 用于不同 User-Agent/語言生成不同緩存副本 |
👉 CDN 可以配置“強緩存”或“協商緩存”,也可結合自身規則(如 URL 后綴、參數名等)自定義策略。
🚀 CDN 緩存的好處
優勢 | 描述 |
---|---|
? 提升訪問速度 | 用戶從就近節點獲取資源,降低延遲 |
🔁 降低源站壓力 | 靜態內容不再頻繁請求源站 |
💥 提高抗壓能力 | 多節點分發請求,防止高峰宕機 |
🌍 跨地域加速 | 國內外訪問都能快 |
🔧 示例:設置緩存響應頭(Nginx)
location /static/ {root /var/www/html;expires 1h; # 設置緩存1小時add_header Cache-Control "public";
}
? 小結
問題 | 答案 |
---|---|
CDN 緩存和本地緩存一樣嗎? | 類似,都是減少重復請求。但 CDN 是服務器層緩存 |
CDN 緩存在哪? | 緩存在 CDN 邊緣節點(距離用戶近的服務器) |
什么時候會回源? | 緩存未命中,或者緩存過期時 |
📌 總結
- 想讓客戶端緩存數據,關鍵是設置好 HTTP 響應頭
- OpenResty 本身不自動幫你做瀏覽器緩存,你要顯式加
Cache-Control
、Expires
、ETag
等頭 content_by_lua
里也能加ngx.header[...]
發送這些頭部