跳到主要內容

使用邊緣端包含

編輯此頁面

閘道快取是提升網站效能的好方法。但它們有一個限制:它們只能快取整個頁面。如果您的頁面包含動態區塊,例如使用者名稱或購物車,您就束手無策了。幸運的是,Symfony 為這些情況提供了解決方案,基於一種稱為 ESI 或邊緣端包含的技術。Akamai 在 2001 年編寫了此規範,它允許頁面的特定部分具有與主頁面不同的快取策略。

ESI 規範描述了您可以嵌入在頁面中的標籤,以與閘道快取進行通訊。Symfony 中僅實作了一個標籤 include,因為這是 Akamai 環境之外唯一有用的標籤

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
    <body>
        <!-- ... some content -->

        <!-- Embed the content of another page here -->
        <esi:include src="http://..."/>

        <!-- ... more content -->
    </body>
</html>

注意

從範例中注意到,每個 ESI 標籤都需要一個完整的 URL。ESI 標籤代表一個可以通過給定的 URL 獲取的頁面片段。

當處理請求時,閘道快取會從其快取中提取整個頁面,或從後端應用程式請求頁面。如果回應包含一個或多個 ESI 標籤,這些標籤會以相同的方式處理。換句話說,閘道快取要麼從其快取中檢索包含的頁面片段,要麼再次從後端應用程式請求頁面片段。當所有 ESI 標籤都已解析時,閘道快取會將每個標籤合併到主頁面中,並將最終內容發送到客戶端。

所有這些都在閘道快取層級透明地發生(即在您的應用程式之外)。正如您將看到的,如果您選擇利用 ESI 標籤,Symfony 使包含它們的過程幾乎毫不費力。

在 Symfony 中使用 ESI

首先,要使用 ESI,請確保在您的應用程式配置中啟用它

1
2
3
4
# config/packages/framework.yaml
framework:
    # ...
    esi: true

現在,假設您有一個相對靜態的頁面,除了內容底部的跑馬燈新聞。使用 ESI,您可以將跑馬燈新聞與頁面的其餘部分獨立快取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Controller/DefaultController.php
namespace App\Controller;

// ...
class DefaultController extends AbstractController
{
    public function about(): Response
    {
        $response = $this->render('static/about.html.twig');
        $response->setPublic();
        $response->setMaxAge(600);

        return $response;
    }
}

在這個範例中,回應被標記為公開,使整個頁面對於所有請求都可快取,生命週期為十分鐘。接下來,通過嵌入一個動作,將跑馬燈新聞包含在模板中。這是通過 render() 助手完成的(更多詳細資訊,請參閱如何在模板中嵌入控制器)。

由於嵌入的內容來自另一個頁面(或控制器),Symfony 使用標準的 render 助手來配置 ESI 標籤

1
2
3
4
5
6
7
{# templates/static/about.html.twig #}

{# you can use a controller reference #}
{{ render_esi(controller('App\\Controller\\NewsController::latest', { 'maxPerPage': 5 })) }}

{# ... or a URL #}
{{ render_esi(url('latest_news', { 'maxPerPage': 5 })) }}

通過使用 esi 渲染器(通過 render_esi() Twig 函數),您告訴 Symfony 該動作應渲染為 ESI 標籤。您可能想知道為什麼要使用助手而不是自己編寫 ESI 標籤。那是因為即使沒有安裝閘道快取,使用助手也能使您的應用程式正常運作。

提示

正如您在下面看到的,您傳遞的 maxPerPage 變數可用作控制器的參數(即 $maxPerPage)。通過 render_esi 傳遞的變數也成為快取鍵的一部分,以便您為變數和值的每個組合擁有唯一的快取。

當使用預設的 render() 函數(或將渲染器設定為 inline)時,Symfony 會在將回應發送到客戶端之前,將包含的頁面內容合併到主頁面中。但是,如果您使用 esi 渲染器(即調用 render_esi())*並且* Symfony 檢測到它正在與支援 ESI 的閘道快取進行通訊,它會生成一個 ESI include 標籤。但是,如果沒有閘道快取,或者它不支援 ESI,Symfony 只會將包含的頁面內容合併到主頁面中,就像您使用 render() 時一樣。

注意

如果閘道快取的請求包含 Surrogate-Capability HTTP 標頭,並且該標頭的值在任何位置包含 ESI/1.0 字串,Symfony 則認為該閘道快取支援 ESI。

現在,嵌入的動作可以完全獨立於主頁面指定自己的快取規則

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Controller/NewsController.php
namespace App\Controller;

use Symfony\Component\HttpKernel\Attribute\Cache;
// ...

class NewsController extends AbstractController
{
    #[Cache(smaxage: 60)]
    public function latest(int $maxPerPage): Response
    {
        // ...
    }
}

在這個範例中,嵌入的動作也被公開快取,因為內容對於所有請求都是相同的。但是,在其他情況下,您可能需要根據您的需求,使此回應成為非公開的,甚至不可快取的。

將以上所有程式碼放在一起,使用 ESI,整個頁面快取將有效 600 秒,但新聞組件快取僅持續 60 秒。

當使用控制器參考時,ESI 標籤應將嵌入的動作引用為可訪問的 URL,以便閘道快取可以獨立於頁面的其餘部分獲取它。Symfony 負責為任何控制器參考生成唯一的 URL,並且由於 FragmentListener 必須在您的配置中啟用,因此它能夠正確地路由它們

1
2
3
4
# config/packages/framework.yaml
framework:
    # ...
    fragments: { path: /_fragment }

ESI 渲染器的一個巨大優勢是,您可以根據需要使您的應用程式盡可能動態,同時盡可能少地訪問應用程式。

警告

片段監聽器僅回應已簽署的請求。僅當使用片段渲染器和 render_esi Twig 函數時,請求才被簽署。

render_esi 助手支援另外三個有用的選項

alt
用作 ESI 標籤上的 alt 屬性,允許您指定在找不到 src 時使用的替代 URL。
ignore_errors
如果設定為 true,則會將 onerror 屬性添加到 ESI,值為 continue,表示在發生故障時,閘道快取將靜默地移除 ESI 標籤。
absolute_uri
如果設定為 true,將生成絕對 URI。預設值false
本作品,包括程式碼範例,均根據 Creative Commons BY-SA 3.0 授權條款授權。
目錄
    版本