跳到內容

HTTP 快取

編輯此頁

豐富的網路應用程式的本質意味著它們是動態的。無論您的應用程式多麼有效率,每個請求始終包含比服務靜態檔案更多的額外開銷。通常,這沒問題。但是,當您需要請求速度如閃電般快速時,您需要 HTTP 快取。

站在巨人的肩膀上進行快取

透過 HTTP 快取,您可以快取頁面的完整輸出(即回應),並在後續請求中完全繞過您的應用程式。快取完整回應對於高度動態的網站並非總是可行,還是可行?透過邊緣端包含 (ESI),您可以在您網站的僅片段上使用 HTTP 快取的功能。

Symfony 快取系統與眾不同,因為它依賴於 RFC 7234 - 快取 中定義的 HTTP 快取的簡潔性和強大功能。Symfony 沒有重新發明快取方法,而是擁抱定義網路上基本通訊的標準。一旦您了解基本的 HTTP 驗證和過期快取模型,您將準備好掌握 Symfony 快取系統。

由於使用 HTTP 快取並非 Symfony 獨有,因此已經存在許多關於該主題的文章。如果您是 HTTP 快取的新手,強烈建議 Ryan Tomayko 的文章 快取的作用。另一個深入的資源是 Mark Nottingham 的 快取教學

使用閘道快取進行快取

當使用 HTTP 快取時,快取與您的應用程式完全分離,並位於您的應用程式和發出請求的用戶端之間。

快取的工作是接受來自用戶端的請求,並將它們傳回您的應用程式。快取也將接收來自您的應用程式的回應,並將它們轉發給用戶端。快取是用戶端和您的應用程式之間請求-回應通訊的「中間人」。

在此過程中,快取將儲存每個被視為「可快取」的回應(請參閱 HTTP 快取)。如果再次請求相同的資源,快取會將快取的回應傳送給用戶端,完全忽略您的應用程式。

這種快取類型稱為 HTTP 閘道快取,並且存在許多,例如 Varnish反向代理模式下的 Squid 和 Symfony 反向代理。

提示

閘道快取有時稱為反向代理快取、代理快取,甚至 HTTP 加速器。

Symfony 反向代理

Symfony 隨附一個以 PHP 撰寫的反向代理(即閘道快取)。它不像 Varnish 那樣是功能完善的反向代理快取,但它是入門的好方法。

提示

有關設定 Varnish 的詳細資訊,請參閱 如何使用 Varnish 加速我的網站

使用 framework.http_cache 選項為 prod 環境 啟用代理

1
2
3
4
# config/packages/framework.yaml
when@prod:
    framework:
        http_cache: true

核心將立即充當反向代理:快取來自您應用程式的回應並將其傳回給用戶端。

代理具有合理的預設組態,但可以透過 一組選項 進行微調。

偵錯模式 下,Symfony 會自動將 X-Symfony-Cache 標頭新增至回應。您也可以使用 trace_level 組態選項,並將其設定為 noneshortfull 以新增此資訊。

short 將僅新增主要請求的資訊。它以簡潔的方式撰寫,使其易於記錄在您的伺服器記錄檔中。例如,在 Apache 中,您可以在 LogFormat 格式語句中使用 %{X-Symfony-Cache}o。此資訊可用於擷取有關您路由的快取效率的一般資訊。

提示

您可以使用 trace_header 組態選項變更用於追蹤資訊的標頭名稱。

當您開發網站或將網站部署到無法安裝 PHP 程式碼以外任何東西的共用主機時,Symfony 反向代理是一個很棒的工具。但是由於是用 PHP 撰寫的,因此它無法像用 C 撰寫的代理一樣快速。

幸運的是,由於所有反向代理實際上都是相同的,因此您應該能夠切換到更強大的工具(例如 Varnish),而不會有任何問題。請參閱 如何使用 Varnish

讓您的回應可 HTTP 快取

一旦您新增了反向代理快取(例如 Symfony 反向代理或 Varnish),您就可以快取您的回應了。為此,您需要溝通到您的快取,哪些回應是可快取的以及快取多久。這是透過在回應上設定 HTTP 快取標頭來完成的。

HTTP 指定了四個回應快取標頭,您可以設定它們以啟用快取

  • Cache-Control
  • Expires
  • ETag
  • Last-Modified

這四個標頭用於透過兩種不同的模型來協助快取您的回應

  1. 過期快取 用於將您的完整回應快取特定時間量(例如 24 小時)。簡單,但快取失效更困難。
  2. 驗證快取 更複雜:用於快取您的回應,但允許您在內容變更時立即動態使其失效。

您將讀到的所有 HTTP 標頭都不是由 Symfony 發明的!它們是整個網路上網站使用的 HTTP 規格的一部分。若要深入了解 HTTP 快取,請查看文件 RFC 7234 - 快取RFC 7232 - 條件請求

強烈建議身為網頁開發人員的您閱讀規格。它的清晰度和強大功能(甚至在創建後十五年以上)非常寶貴。不要被規格的外觀嚇倒 - 其內容比其封面更精美!

過期快取

快取回應的最簡單方法是將其快取特定時間量

1
2
3
4
5
6
7
8
9
// src/Controller/BlogController.php
use Symfony\Component\HttpKernel\Attribute\Cache;
// ...

#[Cache(public: true, maxage: 3600, mustRevalidate: true)]
public function index(): Response
{
    return $this->render('blog/index.html.twig', []);
}

由於此新程式碼,您的 HTTP 回應將具有以下標頭

1
Cache-Control: public, maxage=3600, must-revalidate

這會告知您的 HTTP 反向代理將此回應快取 3600 秒。如果任何人在 3600 秒之前再次請求此 URL,則根本不會點擊您的應用程式。如果您使用的是 Symfony 反向代理,請查看 X-Symfony-Cache 標頭,以取得有關快取命中和未命中的偵錯資訊。

提示

請求的 URI 用作快取金鑰(除非您變更)。

這提供了出色的效能,並且易於使用。但是,不支援快取失效。如果您的內容變更,您需要等到快取過期頁面才會更新。

提示

實際上,您可以手動使您的快取失效,但它不是 HTTP 快取規格的一部分。請參閱 快取失效

如果您需要為許多不同的控制器動作設定快取標頭,請查看 FOSHttpCacheBundle。它提供了一種根據 URL 模式和其他請求屬性定義快取標頭的方法。

最後,有關過期快取的更多資訊,請參閱 HTTP 快取過期

驗證快取

透過過期快取,您說「快取 3600 秒!」。但是,當有人更新快取內容時,在快取過期之前,您不會在您的網站上看到該內容。

如果您需要立即看到更新的內容,您需要使您的快取失效使用驗證快取模型。

有關詳細資訊,請參閱 HTTP 快取驗證

安全方法:僅快取 GET 或 HEAD 請求

HTTP 快取僅適用於「安全」HTTP 方法(例如 GET 和 HEAD)。這表示三件事

  • 不要嘗試快取 PUT 或 DELETE 請求。它不會運作,而且有充分的理由。這些方法旨在在變更應用程式狀態時使用(例如刪除部落格文章)。快取它們會阻止某些請求點擊和變更您的應用程式。
  • POST 請求通常被認為是不可快取的,但是當它們包含明確的新鮮度資訊時,它們可以被快取。但是,POST 快取並未廣泛實作,因此如果可能,您應該避免使用它。
  • 當回應 GET 或 HEAD 請求時,您絕不應該變更應用程式的狀態(例如更新部落格文章)。如果這些請求被快取,則未來的請求可能實際上不會點擊您的伺服器。

更多回應方法

Response 類別提供了許多與快取相關的更多方法。以下是最有用的方法

1
2
3
4
5
// marks the Response stale
$response->expire();

// forces the response to return a proper 304 response with no content
$response->setNotModified();

此外,大多數與快取相關的 HTTP 標頭都可以透過單個 setCache() 方法設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// use this method to set several cache settings in one call
// (this example lists all the available cache settings)
$response->setCache([
    'must_revalidate'  => false,
    'no_cache'         => false,
    'no_store'         => false,
    'no_transform'     => false,
    'public'           => true,
    'private'          => false,
    'proxy_revalidate' => false,
    'max_age'          => 600,
    's_maxage'         => 600,
    'immutable'        => true,
    'last_modified'    => new \DateTime(),
    'etag'             => 'abcdef'
]);

提示

當使用 #[Cache] 屬性時,所有這些選項也都可用。

快取失效

快取失效不是 HTTP 規格的一部分。儘管如此,在更新您網站上的某些內容後立即刪除各種 HTTP 快取項目可能非常有用。

有關詳細資訊,請參閱 快取失效

使用邊緣端包含

當頁面包含動態部分時,您可能無法快取整個頁面,而只能快取部分頁面。閱讀 使用邊緣端包含 以了解如何為您頁面的特定部分設定不同的快取策略。

HTTP 快取和使用者工作階段

每當在請求期間啟動工作階段時,Symfony 都會將回應轉換為私有的不可快取回應。這是最佳的預設行為,以防止快取私有使用者資訊(例如購物車、使用者個人資料詳細資訊等),並將其暴露給其他訪客。

但是,即使是使用工作階段的請求,在某些情況下也可以快取。例如,與某些使用者群組相關的資訊可以為屬於該群組的所有使用者快取。處理這些進階快取情境超出了 Symfony 的範圍,但可以使用 FOSHttpCacheBundle 來解決。

為了停用 Symfony 預設行為(使使用工作階段的請求不可快取),請將以下內部標頭新增至您的回應,Symfony 將不會修改它

1
2
3
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;

$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');

總結

Symfony 的設計旨在遵循經過驗證的規則:HTTP。快取也不例外。掌握 Symfony 快取系統意味著熟悉 HTTP 快取模型並有效地使用它們。這表示,除了僅依賴 Symfony 文件和程式碼範例之外,您還可以存取與 HTTP 快取和閘道快取(例如 Varnish)相關的大量知識。

本作品,包括程式碼範例,均根據 Creative Commons BY-SA 3.0 授權條款授權。
目錄
    版本