在優化網頁速度時,常會使用 cache 的機制來減少 server 負載, client 資源等待時間。

比如

  • server 前面會架一台 cdn 服務, cache 一些靜態檔案…等等。
  • server 可能會使用 redis, 來 cache 需要做大量計算的結果,降低負載。

這篇則是要介紹有哪些 http header 可以善用在 client 端(瀏覽器)來優化網頁速度,檢查是否有成功 cache 可以參考此篇文章

  • Expires

最早在 http 1.0 就存在的 header, 使用方式為 Expires[date] (日期格式必須符合 RFC1123)

例如: Expires: Wed, 5 Mar 2018 11:00:00 GMT

用法為設定一個確切的日期,當 client 端時間小於 response header (Expires) 時間時,則會使用 cache.

由於 client 端的日期是跟隨作業系統的時間,因此可能因為使用者的設定不同,而不如預期的 cache,因此在  http 1.1 後建議使用  cache-control header

根據 RFC2616 描述 Expires header 需要注意的有以下兩點,

1. Expires 會被 cache-control 及 max-ageheader 覆寫

2. 若 date 格式不符合 RFC1123 所規範之格式,等同於不 cache

3. 若 Cache-Control header 存在並配合 max-age 設定將會 overwrite 此 header

RFC2616:

Note: if a response includes a Cache-Control field with the max- age directive (see section 14.9.3), that directive overrides the Expires field.

  • Pragma

此 header 是在 http 1.0 時的 header, 常與 Expires 一起使用,用法為 Pragma: no-cache;

根據 RFC7234 說明此 header 等同於在 http1.1的 Cache-Control: no-cache

另外,要注意的是在 http 1.1 後當 Cache-Control header  存在時,此 header 會被忽略。

RFC7234:

When the Cache-Control header field is also present and understood in a request, Pragma is ignored.

  • Cache-Control

此 header 為 http1.1 所定義的,整合了上面 http 1.0 的 Expires 與 Pragma

根據 RFC2616 說明此 header 定義了許多 directive,並且分為 request(client)/response(server) 不同的使用情境。

cache-control 包含了許多的  directive及概念,大體上可以參考這張圖

以下詳細介紹在  request  及 response 常見的幾個 directive

request/response:

1. private: 此  cache 是私有的,只有 client (browser) 可以儲存  cache,常用於個人化敏感資料或像是 api response。

2. public: 此  cache  為公有共享的,中間傳輸的  ISP, proxy 及  cdn  服務商都可以儲存  cache,常用於公用的靜態檔案,像是 js, css 及圖片等 asset。

3. max-age: 設定 cache 多久(秒)過期

相對於 http1.0 的 Expires header,在 http 1.0 的 Expires 所設定的為絕對時間(e.g. Expires: Wed, 5 Mar 2018 11:00:00 GMT),但由於 client(browser/os) 端的時間是使用者可更改的,因此可能導致 Expires 時間與 http header reponse 時間不同步造成 cache 無法如預期運作。

要注意的地方是在 RFC2616 中有提及 max-age 會覆蓋 http1.0 的 Expires

If a response includes both an Expires header and a max-age directive, the max-age directive overrides the Expires header, even if the Expires header is more restrictive.

4. no-cache: 要使用  cache 時必須與做 revalidate,可以儲存  cache。

舉例來說當 server 設定  cache-contorl: no-cache; 時,每次發出的  request 都一定會發  request 與 server  確認是否有內容的更動,若 server  回傳 304 (Not Modified) 則使用  cache 反之則拿取新內容。

ps.  與 Pragma: no-cache; 相等

5. no-store: 不使用任何 cache,並不儲存 cache。

如上解釋,完全不使用  cache,每次都向對方拿內容。

6. no-transform: 不要對傳輸內容做任何轉碼。

常見的地方為 proxy 或  browser 為了減少傳輸內容及流量,會對傳輸的圖片格式做壓縮換轉換,此 header 可避免被轉碼。

request:

1. max-stale: 設定接受過期多久秒的 cache

舉例來說若上次 request 從 response header 得到了 Expires: Wed, 5 Mar 2018 11:00:00 GMT,因此當我們在 2018/03/05 11:01:00 時發送 cache-control: max-stale=120 request, 由於此 cache 僅過期 60秒(<= max-stale),因此是不會真實發送 request 到 server 而是使用cache 。

除此之外,也可以設置  cache-control: max-stale 不論過期多久都使用 cache。

2. min-fresh: 設定接受在距離多久過期的 cache

舉例來說若上次 request 從  respinse  得到了 Expires: Wed, 5 Mar 2018 11:00:00 GMT,因此當我們在 2018/03/05 10:59 分以後發送 cache-control: min-fresh=60  request 都會視為 cache 已經不新鮮而發送至 server。

response:

1. must-revalidate: 在 cache max-age 到期時,盡管有設  max-stale 延長  cache  新鮮度也應該要做 validate。

相較 no-cache 較寬鬆

2. proxy-revalidate: 設定  public cache 時 proxy 的 validate

根據 RFC2616

The proxy-revalidate directive has the same meaning as the must-revalidate directive, except that it does not apply to non-shareduser agent caches.

3. s-max-age: 設定  public cache 時 proxy 的 max-age

設定中間的 cdn, proxy 或 ISP 的 cache。

根據 RFC2616

The s- maxage directive is always ignored by a private cache.

參考資料:

https://blog.techbridge.cc/2017/06/17/cache-introduction/

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-tw

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires

https://tools.ietf.org/html/rfc2616#section-14.21

https://tools.ietf.org/html/rfc7234#section-5.4

Leave a Reply