作者:自由的巨浪
https://juejin.cn/post/7406143794000019506
開(kāi)啟HTTP緩存是前端性能優(yōu)化中提高資源加載效率的重要手段。以下是幾個(gè)關(guān)鍵點(diǎn):
減少重復(fù)請(qǐng)求:通過(guò)緩存機(jī)制,瀏覽器可以存儲(chǔ)已請(qǐng)求過(guò)的資源,減少對(duì)服務(wù)器的重復(fù)請(qǐng)求。
設(shè)置緩存頭:在服務(wù)器端設(shè)置合適的Cache-Control
、Expires
或ETag
響應(yīng)頭,告訴瀏覽器如何緩存資源。
區(qū)分靜態(tài)和動(dòng)態(tài)資源:靜態(tài)資源(如圖片、CSS、JS文件)可以設(shè)置較長(zhǎng)的緩存時(shí)間,而動(dòng)態(tài)內(nèi)容則需要更短的緩存時(shí)間或使用驗(yàn)證緩存。
利用瀏覽器緩存:合理配置服務(wù)端緩存策略,讓瀏覽器自動(dòng)處理緩存,減少不必要的網(wǎng)絡(luò)請(qǐng)求。
更新緩存策略:當(dāng)資源更新時(shí),確保使用新的緩存策略,如改變文件名或使用Last-Modified
和ETag
頭來(lái)驗(yàn)證緩存。
監(jiān)控緩存效果:使用瀏覽器的開(kāi)發(fā)者工具監(jiān)控資源的緩存情況,確保緩存策略按預(yù)期工作。
通過(guò)開(kāi)啟HTTP緩存,可以顯著減少頁(yè)面加載時(shí)間,提升用戶體驗(yàn)。
以下是正文:
導(dǎo)讀
開(kāi)啟 HTTP 緩存是前端性能優(yōu)化手段中最常見(jiàn)的方法之一。開(kāi)啟 HTTP 緩存后,當(dāng)瀏覽器請(qǐng)求資源時(shí),提供資源的服務(wù)器可以告知瀏覽器應(yīng)該臨時(shí)存儲(chǔ)或緩存該資源多長(zhǎng)時(shí)間。
只要資源的緩存沒(méi)有過(guò)期,對(duì)于針對(duì)該資源的任何后續(xù)請(qǐng)求,瀏覽器將使用其本地副本,而不是從網(wǎng)絡(luò)獲取。也就有效的減少了 HTTP 請(qǐng)求,可以顯著地縮短重復(fù)訪問(wèn)的網(wǎng)頁(yè)加載時(shí)間。
NGINX 服務(wù)器端配置 HTTP 緩存
與啟用 Gzip 壓縮實(shí)現(xiàn)手段類似,開(kāi)啟 HTTP 緩存的操作也是在服務(wù)器端配置實(shí)現(xiàn)。本文還是以 NGINX 服務(wù)器為例,介紹如何在 NGINX 服務(wù)器配置 HTTP 緩存。
開(kāi)啟 HTTP 緩存的實(shí)際操作配置就是配置 Expires 頭,并且盡量設(shè)置一個(gè)長(zhǎng)久的 Expires。用 lighthouse 官方文檔的說(shuō)法是:采用高效的緩存政策提供靜態(tài)資源。 來(lái)看看 NGINX 服務(wù)器的配置吧:
cache_expiration.conf
與配置 gzip 時(shí)一樣,緩存的配置信息,也建議單獨(dú)保存到獨(dú)立的配置文件。然后使用 include
在 nginx.conf 文件中引用配置。
http {
# 其它配置
# Specify file cache expiration.
include web_performance/cache_expiration.conf;
}
在 nginx.conf 的 http 模塊中引入cache_expiration.conf 文件的緩存配置,這樣只要是通過(guò)當(dāng)前 NGINX 服務(wù)配置的 Web 站點(diǎn)也就都開(kāi)啟了 HTTP 緩存了。
cache_expiration.conf 配置信息如下:
map $sent_http_content_type $expires {
default 1M;
# No content
'' off;
# CSS
~*text/css 1y;
# Data interchange
~*application/atom\+xml 1h;
~*application/rdf\+xml 1h;
~*application/rss\+xml 1h;
~*application/json 0;
~*application/ld\+json 0;
~*application/schema\+json 0;
~*application/geo\+json 0;
~*application/xml 0;
~*text/calendar 0;
~*text/xml 0;
# Favicon (cannot be renamed!) and cursor images
~*image/vnd.microsoft.icon 1w;
~*image/x-icon 1w;
# HTML
~*text/html 0;
# JavaScript
~*application/javascript 1y;
~*application/x-javascript 1y;
~*text/javascript 1y;
# Manifest files
~*application/manifest\+json 1w;
~*application/x-web-app-manifest\+json 0;
~*text/cache-manifest 0;
# Markdown
~*text/markdown 0;
# Media files
~*audio/ 1M;
~*image/ 1M;
~*video/ 1M;
# WebAssembly
~*application/wasm 1y;
# Web fonts
~*font/ 1M;
~*application/vnd.ms-fontobject 1M;
~*application/x-font-ttf 1M;
~*application/x-font-woff 1M;
~*application/font-woff 1M;
~*application/font-woff2 1M;
# Other
~*text/x-cross-domain-policy 1w;
}
# 時(shí)間根據(jù)變量 $expires 的配置匹配
expires $expires;
緩存哪些資源,緩存多久?
這個(gè) cache_expiration.conf 文件的配置可能要比大家通常看到的配置要復(fù)雜一些,不過(guò)應(yīng)該也是很容易看懂的。其主要策略就是針對(duì)不會(huì)經(jīng)常調(diào)整的文件類型,盡量給一個(gè)長(zhǎng)久的 Expires。
另外,通過(guò) cache_expiration.conf 配置文件的內(nèi)容,也可以明確的發(fā)現(xiàn),緩存的基本上都是靜態(tài)資源,并且不同的靜態(tài)資源緩存的時(shí)長(zhǎng)是不一樣的。
例如 .css 和 .js 文件,這里的配置就給了 1y(一年),字體和圖片資源也設(shè)置了 1M(一個(gè)月),而經(jīng)常請(qǐng)求的 json 數(shù)據(jù)則沒(méi)有緩存。$expires 變量會(huì)根據(jù)不同的資源類型,定義不同的合適的緩存時(shí)間。
Lighthouse 的緩存策略
再看看前端性能分析工具 Lighthouse。如果滿足以下所有條件,則 Lighthouse 會(huì)認(rèn)為資源可緩存:
- 資源具有
200
、203
或 206
HTTP 狀態(tài)代碼[1]。
cache-control.conf
除了配置 Expires 頭的配置,另外一個(gè)重要配置就是 cache-control.conf
文件。cache-control.conf
文件中就是針對(duì) Cache-Control 首部字段的配置:
map $sent_http_content_type $cache_control {
default 'public, immutable, stale-while-revalidate';
# No content
'' 'no-store';
# Manifest files
~*application/manifest\+json 'public';
~*text/cache-manifest ''; # `no-cache` (*)
# Assets
~*image/svg\+xml 'public, immutable, stale-while-revalidate';
# Data interchange
~*application/(atom|rdf|rss)\+xml 'public, stale-while-revalidate';
# Documents
~*text/html 'private, must-revalidate';
~*text/markdown 'private, must-revalidate';
~*text/calendar 'private, must-revalidate';
# Data
~*json ''; # `no-cache` (*)
~*xml ''; # `no-cache` (*)
}
也是在 nginx.conf
的 http 模塊中引入:
http {
# 省略其它配置...
# Add Cache-Control.
include web_performance/cache-control.conf;
}
跟 Expires 的配置類似,$cache_control
變量在此 NGINX 配置的所有 Web 站點(diǎn)就都可以訪問(wèn)該變量了。Cache-Control 中可用的指令在稍后的介紹 Cache-Control 首部字段章節(jié)會(huì)詳細(xì)介紹。
與緩存相關(guān)的 HTTP 首部字段
HTTP 緩存配置完畢后,在我們請(qǐng)求的靜態(tài)資源的服務(wù)器響應(yīng)頭中就可以看到 Expires 首部字段信息了:
大家可以根據(jù)自己的情況調(diào)整這里的配置,確定不怎么變動(dòng)的資源,還是盡量給一個(gè)長(zhǎng)久的 Expires。需要說(shuō)明一下,HTML 頁(yè)面通常視作動(dòng)態(tài)資源,建議是不要設(shè)置 Expires 頭的(稍后的章節(jié)中有示例會(huì)給出針對(duì) HTML 頁(yè)面的配置細(xì)節(jié))。
因?yàn)槿绻?HTML 文件緩存了,緩存期間不更新,那么我們?cè)谥付〞r(shí)間內(nèi)永遠(yuǎn)沒(méi)法取到更新后的 js 和 css 或者其它靜態(tài)資源。所以,HTML 緩存另一個(gè)策略是:不緩存html
# HTML
~*text/html 0;
另外,如果不希望配置一個(gè)全局的靜態(tài)資源的 Expires 頭,可以去掉cache_expiration.conf
文件最底部的配置:
# expires $expires
調(diào)整后,在 nginx.conf 配置文件中引入的就只是針對(duì)不同靜態(tài)文件過(guò)期時(shí)間變量 $expires
的配置。這樣就不會(huì)出現(xiàn) NGINX 服務(wù)器上所有配置的所有 Web 站點(diǎn)都使用相同的 Expires 頭的緩存配置,但又都可以訪問(wèn) $expires 變量了。
到這里,關(guān)于在 NGINX 服務(wù)配置 HTTP 緩存的操作內(nèi)容就結(jié)束了。是不是很容易?
Cache-Control 和 Expires 首部字段
在解釋緩存如何很好的優(yōu)化靜態(tài)資源傳輸速度前,需要跟大家聊聊 2 個(gè) HTTP 首部字段 - Cache-Control 和 Expires。
Expires 首部字段
由于 Expires 頭使用一個(gè)特定時(shí)間:
Wed, 23 Jul 2025 12:37:27 GMT
這使得 Expires 頭有一定的局限性,因?yàn)?Expires 頭要求服務(wù)器和客戶端的時(shí)間要嚴(yán)格同步。如果本地電腦調(diào)整了時(shí)間,超過(guò)了 Exipres 頭設(shè)置的時(shí)間,也會(huì)使緩存過(guò)期。
另外,Exipres 頭會(huì)經(jīng)常檢測(cè)過(guò)期時(shí)間,并且一旦過(guò)期了,又需要再服務(wù)器中配置提供一個(gè)新的日期。所以會(huì)有 Exipres 頭設(shè)置的時(shí)間盡量長(zhǎng)的策略。
Cache-Control 首部字段
為解決 Exipres 頭的這些不足,HTTP 1.1 協(xié)議中引入了 Cache-Control 首部字段。Cache-Control 使用 max-age
指令指定組件被緩存多久。它以秒為單位定義更新時(shí)間。如果從資源被請(qǐng)求開(kāi)始過(guò)去的秒數(shù)小于 max-age,瀏覽器就會(huì)使用緩存版本。它可以消除 Expires 頭對(duì)于服務(wù)器和客戶端的時(shí)間必須同步的限制。對(duì)于不支持 Cache-Control 首部字段的瀏覽器,我們?nèi)匀恍枰?Expires 頭,因此一般都會(huì)同時(shí)設(shè)置 Cache-Control 和 Expires 首部字段。在支持 Cache-Control 頭的瀏覽器,max-age 指定將重寫(xiě) Expires 頭。這也是為什么前文的截圖中同時(shí)出現(xiàn)了 Cache-Control 和 Expires 首部字段的響應(yīng)信息。
max-age 指定的設(shè)置策略也和 Expires 頭一致,盡量設(shè)置一個(gè)較長(zhǎng)的時(shí)間。最大可以設(shè)置 10 年,一般都設(shè)置至少 30 天以上。
注意: 緩存持續(xù)時(shí)間過(guò)長(zhǎng)的一個(gè)風(fēng)險(xiǎn)就是您的用戶不會(huì)看到靜態(tài)文件的更新。若要避免此問(wèn)題,可以將構(gòu)建工具配置為在靜態(tài)資源文件名中嵌入一個(gè)哈希,以使每個(gè)版本都是唯一的,從而提示瀏覽器從服務(wù)器提取新版本。
Cache-Control 首部字段常用指令
除 max-age 指定外,其它常用的指令還有:
- public:表明響應(yīng)可以被任何對(duì)象(包括:發(fā)送請(qǐng)求的客戶端,代理服務(wù)器,等等)緩存。表示相應(yīng)會(huì)被緩存,并且在多用戶間共享。默認(rèn)是 public。
- private:表明響應(yīng)只能被單個(gè)用戶緩存,不能作為共享緩存(即代理服務(wù)器不能緩存它),可以緩存響應(yīng)內(nèi)容。響應(yīng)只作為私有的緩存,不能在用戶間共享。如果要求HTTP認(rèn)證,響應(yīng)會(huì)自動(dòng)設(shè)置為private。
- no-cache:在釋放緩存副本之前,強(qiáng)制高速緩存將請(qǐng)求提交給原始服務(wù)器進(jìn)行驗(yàn)證。指定不緩存響應(yīng),表明資源不進(jìn)行緩存。但是設(shè)置了no-cache之后并不代表瀏覽器不緩存,而是在緩存前要向服務(wù)器確認(rèn)資源是否被更改。因此有的時(shí)候只設(shè)置no-cache防止緩存還是不夠保險(xiǎn),還可以加上private指令,將過(guò)期時(shí)間設(shè)為過(guò)去的時(shí)間。
- only-if-cached:表明客戶端只接受已緩存的響應(yīng),并且不要向原始服務(wù)器檢查是否有更新的拷貝.
- no-store:緩存不應(yīng)存儲(chǔ)有關(guān)客戶端請(qǐng)求或服務(wù)器響應(yīng)的任何內(nèi)容。表示絕對(duì)禁止緩存!
- no-transform:不得對(duì)資源進(jìn)行轉(zhuǎn)換或轉(zhuǎn)變。Content-Encoding, Content-Range, Content-Type 等 HTTP 頭不能由代理修改。例如,非透明代理可以對(duì)圖像格式進(jìn)行轉(zhuǎn)換,以便節(jié)省緩存空間或者減少緩慢鏈路上的流量。no-transform 指令不允許這樣做。
例如我本地的測(cè)試站點(diǎn),針對(duì) HTML 頁(yè)面的配置就使用了 no-cache:
location / {
proxy_pass http://yao;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 省略其它配置...
# 不緩存 index.html
expires -1;
add_header Cache-Control no-store;
# fix history router model in VUE
try_files $uri $uri/ /index.html;
error_page 404 /index.html;
}
說(shuō)明一下,一直在介紹設(shè)置 Expires 頭,卻沒(méi)有介紹如何配置 Cache-Control 頭,直到示例中才展示的設(shè)置 no-store。這是因?yàn)樵?NGINX 服務(wù)器中配置了 Expires 頭,在配置反向代理指定了 HTTP1.1 協(xié)議后:
proxy_http_version 1.1;
NGINX 服務(wù)器會(huì)使用 Cache-Control 頭重寫(xiě) Expires 頭,過(guò)期時(shí)間就是 Expires 頭配置的時(shí)間。因此如果不是像 HTML 文件這樣需要禁止緩存,沒(méi)有額外的 Cache-Control 頭配置。
再以前文的截圖為例,這里獲取到的 js 文件的 max-age 指令的時(shí)長(zhǎng)就和 Expires 頭的過(guò)期時(shí)間一致。
如果資源變化和新鮮度很重要,但仍想獲得緩存的一些速度優(yōu)勢(shì),請(qǐng)使用 no-cache
。瀏覽器仍會(huì)緩存設(shè)置為 no-cache
的資源,但會(huì)先向服務(wù)器進(jìn)行檢查,以確保該資源仍為最新資源。
前文介紹了 Cache-Control 頭允許使用的許多不同的指令,它們可用于自定義瀏覽器如何緩存不同資源,請(qǐng)根據(jù)需要選擇選擇合適的 Cache-Control 頭指令。
最后要特別說(shuō)明,雖然介紹的 Expires 頭和 Cache-Control 頭的 max-age 指令中推薦的策略是盡可能長(zhǎng),但緩存時(shí)間不一定是越長(zhǎng)越好。最終還是應(yīng)該根據(jù)實(shí)際使用情況來(lái)決定資源的最佳緩存時(shí)長(zhǎng)。
Last-Modified Date 和 ETag
Cache-Control 和 Expires 兩個(gè) HTTP 首部字段是用來(lái)指定資源的緩存時(shí)長(zhǎng)的。而服務(wù)器在檢測(cè)緩存的資源是否和原始服務(wù)器上的資源匹配,則使用的是另外 2 種方式:
- 比較最新修改日期(Last-Modified Date)
最新修改時(shí)間(Last-Modified Date)
原始服務(wù)器通過(guò) Last-Modified
響應(yīng)頭來(lái)返回組件的最新修改日期:
Last-Modified: Tue, 25 Jun 2024 20:20:53 GMT
設(shè)置了 Expires 頭后,瀏覽器會(huì)緩存資源和它的最新修改日期。再次請(qǐng)求同一資源時(shí),瀏覽器會(huì)使用 If-Modified-Since
頭將最新修改日期回傳到原始服務(wù)器進(jìn)行比較。如果匹配則返回 304 響應(yīng),而不會(huì)重新下載組件。
實(shí)體標(biāo)簽(ETag)
實(shí)體標(biāo)簽 ETag 是 Web 服務(wù)器和瀏覽器用于確認(rèn)緩存資源的有效性的一種機(jī)制。ETag 在 HTTP 1.1 引入,它是表示組件的特定版本的唯一性的字符串。例如:
Etag: 'b886a62d3dc7da1:0'
它是提供了另一種方式檢測(cè)緩存的資源是否與原始服務(wù)器上的資源是否匹配。ETag 的檢測(cè)機(jī)制要比最新修改時(shí)間更加靈活。例如,如果實(shí)體依據(jù) User-Agent 或者 Accept-Language 頭而改變,實(shí)體的狀態(tài)可以反應(yīng)在 ETag 中。也就是說(shuō) ETag 的唯一字符串的值會(huì)發(fā)生改變。
ETag 的驗(yàn)證機(jī)制是在次訪問(wèn)同一資源的時(shí)候,它會(huì)使用 If-None-Match
頭將 ETag 傳回原服務(wù)器。如果匹配則返回 304 響應(yīng),而不會(huì)重新下載資源。
ETag 的問(wèn)題
通常的 Web 服務(wù)器的架構(gòu)設(shè)計(jì)都是做了高可用的配置的,是由多臺(tái)服務(wù)器組成的集群構(gòu)建而成。例如我本地的測(cè)試站點(diǎn)的負(fù)載均衡的配置:
upstream yao {
server 127.0.0.1:18080;
server 127.0.0.1:18081;
server 127.0.0.1:18082;
}
ETag 有個(gè)問(wèn)題,當(dāng)瀏覽器分別從兩臺(tái)不同的后端集群服務(wù)器中請(qǐng)求同一資源的時(shí)候,兩臺(tái)不同的服務(wù)器的 ETag 是不會(huì)一致的。
當(dāng)然,我們可以通過(guò)在負(fù)載平衡的配置中添加 keepalive
或者設(shè)置服務(wù)器的 weight
權(quán)重,讓同一客戶端盡量從同一服務(wù)器獲取資源,但還是無(wú)法保證會(huì)切換服務(wù)器請(qǐng)求資源。
NGINX 配置反向代理緩存
既然提到了服務(wù)器組成的集群,除了使用普通的靜態(tài)資源的 HTTP 緩存外,我們還可以將服務(wù)器集群中的原始資源緩存到代理服務(wù)器上,也就是配置反向代理緩存,將資源都緩存到 NGINX 服務(wù)器所在的代理服務(wù)器上。
如圖所示,用戶第一次請(qǐng)求資源,NGINX 服務(wù)器會(huì)向集群中的服務(wù)器請(qǐng)求資源,然后緩存下來(lái)。用戶再次請(qǐng)求數(shù)據(jù)的時(shí)候,如果 NGINX 服務(wù)器已經(jīng)緩存了,NGINX 服務(wù)器就會(huì)直接響應(yīng),而不用再向上游的服務(wù)器集群的服務(wù)器請(qǐng)求資源了。這樣就進(jìn)一步優(yōu)化了請(qǐng)求的響應(yīng)速度,也更進(jìn)一步的優(yōu)化了前端性能。
配置反向代理緩存
要配置反向代理緩存,需要在 NGINX 服務(wù)器上配置一個(gè)緩存區(qū)域,指定緩存路徑,目錄層級(jí),共享內(nèi)存的大小等信息。廢話不多說(shuō),直接上配置文件。
proxy_cache_path 指令
proxy_cache_path
是 Nginx 中用于配置反向代理緩存的指令。它定義了緩存存儲(chǔ)的位置、緩存大小、緩存的各種參數(shù)等。反向代理緩存可以極大地提高性能,減少對(duì)后端服務(wù)器的負(fù)載。
還是老規(guī)矩,使用獨(dú)立的 proxy_cache.conf 文件保存 proxy_cache_path
配置,然后在需要的地方 include 配置;
proxy_cache_path ./cache
levels=1:2
keys_zone=cache_static:100m
inactive=1h
max_size=300m
use_temp_path=off;
- proxy_temp_path=./cache: 緩存臨時(shí)目錄路徑;
- levels=1:2: 緩存目錄地層級(jí),默認(rèn)所有緩存文件都放在同一個(gè)目錄下,從而影響緩存的性能,大部分場(chǎng)景推薦使用2級(jí)目錄來(lái)存儲(chǔ)緩存文件;
- keys_zone=cache_static:100m: 在共享內(nèi)存中設(shè)置一塊存儲(chǔ)區(qū)域來(lái)存放緩存的 key 和 metadata(類似使用次數(shù)),這樣 nginx 可以快速判斷一個(gè) request 是否命中或者未命中緩存,1m 可以存儲(chǔ) 8000 個(gè) key,100m 可以存儲(chǔ) 800000 個(gè) key;
- max_size=300m: 最大 cache 空間,如果不指定,會(huì)使用掉所有磁盤(pán)空間(disk space),當(dāng)達(dá)到配額后,會(huì)刪除最少使用的 cache 文件;
- inactive=1d: 未被訪問(wèn)文件在緩存中保留時(shí)間,本配置中如果 60 分鐘未被訪問(wèn)則不論狀態(tài)是否為 expired,緩存控制程序會(huì)刪掉文件,默認(rèn)為10分鐘;需要注意的是,inactive 和 expired 配置項(xiàng)的含義是不同的,expired 只是緩存過(guò)期,但不會(huì)被刪除,inactive 是刪除指定時(shí)間內(nèi)未被訪問(wèn)的緩存文件;
- use_temp_path=off: 如果為 off,則 nginx 會(huì)將緩存文件直接寫(xiě)入指定的 cache 文件中,而不是使用 temp_path 存儲(chǔ),official 建議為 off,避免文件在不同文件系統(tǒng)中不必要的拷貝;
nginx.conf 引用代理緩存配置
proxy_cache_path 是一個(gè)全局性的配置,通常會(huì)在 nginx.conf 配置文件中使用 include 方式引入配置:
http {
# 省略其它配置...
# 代理緩存配置
include web_performance/proxy_cache.conf;
}
這樣只要是此 NGINX 服務(wù)配置的 Web 站點(diǎn),就都可以引用 proxy_cache.conf 的代理緩存配置了。
為 Web 站點(diǎn)的靜態(tài)資源配置反向代理緩存
通常我們都是緩存靜態(tài)資源,所以這里就以我本地的測(cè)試站點(diǎn)的靜態(tài)資源的配置作為示例:
# 上游的服務(wù)器負(fù)載均衡配置
include upstreams/www.yao.com.conf;
server {
listen [::]:80;
listen 80;
server_name www.yao.com;
# 將 http 請(qǐng)求訪問(wèn),跳轉(zhuǎn)到相應(yīng)的 https 訪問(wèn)路徑
return 301 https://$host$request_uri;
}
server {
# 下次介紹配置 HTTPS 和 HTTP2
# listen [::]:443 ssl http2;
listen 443 ssl http2;
server_name www.yao.com;
# 配置證書(shū)信息
include ssl/ssl_engine.conf;
include ssl/default_certificate_files.conf;
include ssl/policy_intermediate.conf;
# 針對(duì)首頁(yè)的配置
location / {
proxy_pass http://yao;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_intercept_errors on;
proxy_next_upstream error timeout invalid_header http_500;
proxy_connect_timeout 2;
add_header X-Upstream $upstream_addr;
proxy_pass_header Authorization;
client_body_in_file_only clean;
client_body_buffer_size 32K;
client_max_body_size 150M;
# 不緩存 index.html
expires -1;
add_header Cache-Control no-store;
# fix history router model in VUE
try_files $uri $uri/ /index.html;
error_page 404 /index.html;
}
# 訪問(wèn)前端站點(diǎn)的靜態(tài)文件的代理配置
# 根據(jù)自己的需要添加靜態(tài)資源的后綴名
location ~* \.(js|css)$ {
proxy_pass http://yao;
# 通用的一些反向代理配置
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 設(shè)置資源緩存的 zone,使用之前配置的 cache_static
proxy_cache cache_static;
# 設(shè)置緩存的 key
proxy_cache_key $host$uri$is_args$args;
# 設(shè)置狀態(tài)碼為 200 和 304 的響應(yīng)可以進(jìn)行緩存,并且緩存時(shí)間為 10 分鐘
# 根據(jù)自己的站點(diǎn)情況配置時(shí)長(zhǎng),時(shí)間臺(tái)長(zhǎng) cache_static 空間很快會(huì)消耗完
proxy_cache_valid 200 304 10m;
# 調(diào)整原服務(wù)器的緩存配置
proxy_ignore_headers Expires Set-Cookie Cache-Control;
proxy_hide_header Cache-Control;
proxy_hide_header Set-Cookie;
# 調(diào)整原服務(wù)器的 Accept-Encoding
proxy_set_header Accept-Encoding 'gzip';
# 被多次用到的資源才緩存,只用一次的無(wú)需代理緩存
proxy_cache_min_uses 2;
# 配置自定義頭 X-Cache 顯示代理緩存命中狀態(tài)
add_header X-Cache $upstream_cache_status;
# 根據(jù)之前的 $expires 匹配的資源文件類型設(shè)置過(guò)期時(shí)間
# 當(dāng)然,你也可以自己根據(jù)需要,直接設(shè)置一個(gè)合適的過(guò)期時(shí)間
expires $expires;
add_header Cache-Control 'public, no-transform';
}
}
$upstream_cache_status 變量監(jiān)測(cè)代理緩存狀態(tài)
NGINX 提供了 $upstream_cache_status
這個(gè)變量來(lái)顯示緩存的狀態(tài).在這里的配置中添加了一個(gè)自定義的 X-Cache 頭,使用 $upstream_cache_status
監(jiān)測(cè)代理緩存的狀態(tài)。以下是 $upstream_cache_status
的可能值:
- MISS - 在緩存中找不到響應(yīng),因此從原始服務(wù)器獲取。然后可以緩存響應(yīng);
- BYPASS - 響應(yīng)是從原始服務(wù)器獲取的,而不是從緩存中提供的,因?yàn)檎?qǐng)求與proxy_cache_bypass指令匹配(請(qǐng)參閱下面的“我可以通過(guò)我的緩存打孔嗎?”)然后可以緩存響應(yīng);
- EXPIRED - 緩存中的條目已過(guò)期。響應(yīng)包含來(lái)自源服務(wù)器的新內(nèi)容;
- STALE - 內(nèi)容過(guò)時(shí),因?yàn)樵挤?wù)器未正確響應(yīng),并且已配置proxy_cache_use_stale;
- UPDATING- 內(nèi)容過(guò)時(shí),因?yàn)楫?dāng)前正在更新條目以響應(yīng)先前的請(qǐng)求,并且配置了proxy_cache_use_stale更新;
- REVALIDATED - 啟用了proxy_cache_revalidate指令,NGINX驗(yàn)證當(dāng)前緩存的內(nèi)容仍然有效(If-Modified-Since或If-None-Match);
- HIT - 響應(yīng)包含直接來(lái)自緩存的有效新鮮內(nèi)容;
默認(rèn)情況下,NGINX 尊重源服務(wù)器的 Cache-Control 頭。它不會(huì)緩存響應(yīng),緩存控制設(shè)置為 Private,No-Cache 或 No-Store 或響應(yīng)頭中的 Set-Cookie。NGINX 僅緩存 GET 和 HEAD 客戶端請(qǐng)求。
# 調(diào)整原服務(wù)器的緩存配置
proxy_ignore_headers Expires Set-Cookie Cache-Control;
proxy_hide_header Cache-Control;
proxy_hide_header Set-Cookie;
前文中的這段配置就是為了啟用代理緩存,用以忽略源服務(wù)器的 Cache-Control 頭。
另外,還特別添加了NGINX 服務(wù)器自己的 Cache-Control 頭的配置:
add_header Cache-Control 'public, no-transform';
表示允許響應(yīng)被被緩存,并且在多用戶間共享。不得對(duì)資源進(jìn)行轉(zhuǎn)換或轉(zhuǎn)變。
再看看 X-Cache 頭,也就是 $upstream_cache_status
的值已經(jīng)是 HIT 狀態(tài),表示該靜態(tài)資源已經(jīng)被代理緩存命中了。
OK,現(xiàn)在讓我們來(lái)看看反向代理緩存都存了些什么:
從截圖我們可以看到,配置的2級(jí)緩存已經(jīng)啟用了。緩存的文件是二進(jìn)制的內(nèi)容,我截取一段用文本編輯器打開(kāi)的數(shù)據(jù)來(lái)看看:
這里的KEY:
KEY: www.yao.com/js/909.86428264.js
正是我們配置的反向代理緩存的中 proxy_cache_key
配置的數(shù)據(jù)格式:
# 設(shè)置緩存的 key
proxy_cache_key $host$uri$is_args$args;
proxy_cache_purge 清除反向代理緩存
若要手動(dòng)清除緩存,可以使用 proxy_cache_purge
模塊。配置代碼如下:
# 用于清除緩存,假設(shè)一個(gè)URL為: https://www.yao.com/#/default
# 訪問(wèn) https://www.yao.com/#/purge/defaut 就可清除該URL的緩存
location ~ /purge(/.*) {
# 設(shè)置只允許指定的IP或IP段才可以清除URL緩存。
allow 127.0.0.1;
deny all;
proxy_cache_purge cache_static $host$uri$is_args$args;
}
這個(gè)清理緩存的路徑應(yīng)該只有特定(運(yùn)維)人員有權(quán)限訪問(wèn),清理緩存。
編譯安裝 Nginx 并且添加 ngx_cache_purge 模塊
另外,proxy_cache_purge
不是 NGINX 服務(wù)器自帶的指令模塊,需要手動(dòng)下載編譯安裝。
第1步:獲取 nginx
在 /etc/nginx/source
下執(zhí)行,具體是在那個(gè)目錄,可以自行決定:
wget http://nginx.org/download/nginx-1.21.0.tar.gz
tar -zxvf nginx-1.12.2.tar.gz
第2步:獲取 ngx_cache_purge
在 /etc/nginx/source
下執(zhí)行,具體是在那個(gè)目錄,可以自行決定,這里建議與下載的 nginx 目錄一致:
wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz
tar -zxvf 2.3.tar.gz
第3步:修改 nginx 安裝配置
./configure --prefix=/etc/nginx \
--with-http_stub_status_module \
--with-http_ssl_module --with-stream \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-pcre \
--add-module=../ngx_cache_purge
--add-module=../ngx_cache_purge
這是新增的,如果要查看以前的 configure 參數(shù),可以使用以下命令查看,然后復(fù)制后再后邊加入需要添加的配置即可。
nginx -V
第4步:編譯安裝
如果以前未安裝過(guò):
make && make install
編譯安裝完成后,配置 nginx。
如果以前已經(jīng)安裝了 nginx 服務(wù)器,需要先停止 nginx 服務(wù):
# 默認(rèn) nginx 已經(jīng)配置為系統(tǒng)服務(wù)
service nginx stop
重新編譯,在 /etc/nginx/source
下執(zhí)行
make
將編譯好的 nginx 文件覆蓋到/etc/nginx/sbin/nginx
:
cp objs/nginx /etc/nginx/sbin/nginx
安裝編譯完成,然后按前文到需要的模塊配置 proxy_cache_purge
, 然后檢測(cè)配置文件是否正確:
nginx -t/T
如果配置檢測(cè)通過(guò),就可以重啟 nginx 服務(wù):
service nginx start
另外,NGINX 服務(wù)器的商業(yè)版 Nginx Plus 中自帶了清理緩存的指令,有興趣的同學(xué)可以自己查閱一下相關(guān)資料,本文僅介紹 NGINX 服務(wù)器免費(fèi)版的配置。
本文到此為止我們已經(jīng)介紹了如何 NGINX 服務(wù)器配置 HTTP 緩存、與換竄相關(guān)的 HTTP 首部字段、如何在 NGIN 服務(wù)器配置反向代理緩存以及如何清理反向代理緩存。所有于開(kāi)啟 HTTP 緩存相關(guān)的配置就都已經(jīng)介紹完畢了。
開(kāi)啟 HTTP 緩存后的性能對(duì)比
最后,還是一起再看看開(kāi)啟 HTTP 緩存后的性能提升對(duì)比吧:
未開(kāi)啟 HTTP 緩存
開(kāi)啟 HTTP 緩存
效果還是很明顯的,特別是像我測(cè)試站點(diǎn)這種 SPA 頁(yè)面,一切都要等 js 資源加載完成了才繪制界面,加載速度至關(guān)重要!資源加載的越快,意味著用戶看到 UI 界面就越快,用戶體驗(yàn)也就越好。
總結(jié)
本文的標(biāo)題是介紹前端性能優(yōu)化,但基本都是在介紹如何配置 NGINX 服務(wù)器。所以要求前端開(kāi)發(fā)工程師需要掌握必要的 NGINX 服務(wù)器相關(guān)的知識(shí)。起碼是跟前端開(kāi)發(fā)或者性能優(yōu)化相關(guān)的知識(shí)點(diǎn)。
然后就是對(duì)于 HTTP 協(xié)議基礎(chǔ)支持的了解,需要知道常用的 HTTP 首部字段的含有,以便于我們分析一些網(wǎng)絡(luò)問(wèn)題。
該文章在 2024/11/7 12:11:37 編輯過(guò)