drupal-cache-contexts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Drupal Cache Contexts

Drupal缓存上下文

Cache contexts define request-dependent cache variations. Analogous to HTTP
Vary
header.
缓存上下文定义了依赖于请求的缓存变体,类似于HTTP的
Vary
头。

When to Use

使用场景

  • Content varies by user role or permissions
  • Content changes based on URL parameters
  • Multi-language sites with localized content
  • Theme-dependent rendering
  • Preventing cache explosion from overly broad contexts
  • 内容随用户角色或权限变化
  • 内容根据URL参数改变
  • 多语言站点的本地化内容
  • 依赖主题的渲染
  • 避免因上下文范围过宽导致的缓存膨胀

Available Contexts

可用上下文

ContextVariationsUse Case
user
Per-user (AVOID)Truly personalized content only
user.roles
Per-role combinationRole-based visibility
user.permissions
Per-permission setPermission-based content
url.path
Per-pathPath-dependent content
url.query_args:key
Per-parameterSort, filter, pagination
languages:language_interface
Per-languageTranslated content
theme
Per-themeTheme-specific rendering
session
Per-sessionSession data (triggers placeholder)
上下文变体类型适用场景
user
按用户区分(需避免)仅用于真正的个性化内容
user.roles
按角色组合区分基于角色的可见性控制
user.permissions
按权限集合区分基于权限的内容展示
url.path
按路径区分依赖路径的内容
url.query_args:key
按参数区分排序、筛选、分页功能
languages:language_interface
按语言区分翻译后的内容
theme
按主题区分主题专属渲染
session
按会话区分会话数据(触发占位符)

Context Hierarchy

上下文层级

user (AVOID - per-user cache explosion)
├── user.is_super_user (2 variations only)
├── user.roles (per role combination)
│   └── user.roles:editor (has specific role?)
└── user.permissions (per permission set)
Rule: Always use the most specific context possible.
user (AVOID - per-user cache explosion)
├── user.is_super_user (2 variations only)
├── user.roles (per role combination)
│   └── user.roles:editor (has specific role?)
└── user.permissions (per permission set)
规则: 始终使用最具体的上下文。

Examples

示例

Example 1: Role-Based Content

示例1:基于角色的内容

Input: "I show different content to editors vs anonymous users"
Output:
php
$build = [
  '#markup' => $this->getRoleBasedContent(),
  '#cache' => [
    'contexts' => ['user.roles'],
  ],
];
输入: "我需要向编辑用户和匿名用户展示不同的内容"
输出:
php
$build = [
  '#markup' => $this->getRoleBasedContent(),
  '#cache' => [
    'contexts' => ['user.roles'],
  ],
];

Example 2: Per-User Content (Use Sparingly)

示例2:按用户区分的内容(谨慎使用)

Input: "I need to show the user's own profile info"
Output:
php
// WARNING: Creates cache entry per user - use lazy_builder instead
$build = [
  '#markup' => $user->getDisplayName(),
  '#cache' => [
    'contexts' => ['user'], // High cardinality!
  ],
];

// BETTER: Use lazy builder for per-user content
$build = [
  '#lazy_builder' => ['my_module.lazy:userName', []],
  '#create_placeholder' => TRUE,
];
输入: "我需要展示用户自己的个人资料信息"
输出:
php
// WARNING: Creates cache entry per user - use lazy_builder instead
$build = [
  '#markup' => $user->getDisplayName(),
  '#cache' => [
    'contexts' => ['user'], // High cardinality!
  ],
];

// BETTER: Use lazy builder for per-user content
$build = [
  '#lazy_builder' => ['my_module.lazy:userName', []],
  '#create_placeholder' => TRUE,
];

Example 3: URL Query Parameters

示例3:URL查询参数

Input: "My listing supports ?sort=date and ?sort=title parameters"
Output:
php
$sort = \Drupal::request()->query->get('sort', 'date');

$build = [
  '#theme' => 'item_list',
  '#items' => $this->getSortedItems($sort),
  '#cache' => [
    'contexts' => ['url.query_args:sort'],
  ],
];
输入: "我的列表支持?sort=date和?sort=title参数"
输出:
php
$sort = \Drupal::request()->query->get('sort', 'date');

$build = [
  '#theme' => 'item_list',
  '#items' => $this->getSortedItems($sort),
  '#cache' => [
    'contexts' => ['url.query_args:sort'],
  ],
];

Example 4: Language-Dependent Content

示例4:依赖语言的内容

Input: "I render translated labels in my block"
Output:
php
$build = [
  '#markup' => $this->t('Welcome'),
  '#cache' => [
    'contexts' => ['languages:language_interface'],
  ],
];
输入: "我在区块中渲染翻译后的标签"
输出:
php
$build = [
  '#markup' => $this->t('Welcome'),
  '#cache' => [
    'contexts' => ['languages:language_interface'],
  ],
];

Example 5: Combined Contexts

示例5:组合上下文

Input: "Content varies by role AND language"
Output:
php
$build = [
  '#markup' => $this->getLocalizedRoleContent(),
  '#cache' => [
    'contexts' => [
      'user.roles',
      'languages:language_interface',
    ],
  ],
];
输入: "内容随角色和语言变化"
输出:
php
$build = [
  '#markup' => $this->getLocalizedRoleContent(),
  '#cache' => [
    'contexts' => [
      'user.roles',
      'languages:language_interface',
    ],
  ],
];

Example 6: Custom Cache Context

示例6:自定义缓存上下文

Input: "I need to vary cache by a custom HTTP header"
Output:
yaml
undefined
输入: "我需要根据自定义HTTP头来区分缓存"
输出:
yaml
undefined

my_module.services.yml

my_module.services.yml

services: cache_context.custom_header: class: Drupal\my_module\Cache\CustomHeaderContext arguments: ['@request_stack'] tags: - { name: cache.context }

```php
namespace Drupal\my_module\Cache;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\CacheContextInterface;

class CustomHeaderContext implements CacheContextInterface {

  public static function getLabel() {
    return t('Custom header');
  }

  public function getContext() {
    $request = $this->requestStack->getCurrentRequest();
    return $request->headers->get('X-Custom-Header', 'default');
  }

  public function getCacheableMetadata() {
    return new CacheableMetadata();
  }
}
php
// Usage
$build['#cache']['contexts'][] = 'custom_header';
services: cache_context.custom_header: class: Drupal\my_module\Cache\CustomHeaderContext arguments: ['@request_stack'] tags: - { name: cache.context }

```php
namespace Drupal\my_module\Cache;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\CacheContextInterface;

class CustomHeaderContext implements CacheContextInterface {

  public static function getLabel() {
    return t('Custom header');
  }

  public function getContext() {
    $request = $this->requestStack->getCurrentRequest();
    return $request->headers->get('X-Custom-Header', 'default');
  }

  public function getCacheableMetadata() {
    return new CacheableMetadata();
  }
}
php
// Usage
$build['#cache']['contexts'][] = 'custom_header';

Example 7: Block with Cache Contexts

示例7:带缓存上下文的区块

Input: "My block shows different actions based on permissions"
Output:
php
class ActionBlock extends BlockBase {

  public function build() {
    $actions = [];
    if (\Drupal::currentUser()->hasPermission('edit content')) {
      $actions[] = 'Edit';
    }
    return ['#markup' => implode(', ', $actions)];
  }

  public function getCacheContexts() {
    return Cache::mergeContexts(
      parent::getCacheContexts(),
      ['user.permissions']
    );
  }
}
输入: "我的区块根据权限展示不同操作"
输出:
php
class ActionBlock extends BlockBase {

  public function build() {
    $actions = [];
    if (\Drupal::currentUser()->hasPermission('edit content')) {
      $actions[] = 'Edit';
    }
    return ['#markup' => implode(', ', $actions)];
  }

  public function getCacheContexts() {
    return Cache::mergeContexts(
      parent::getCacheContexts(),
      ['user.permissions']
    );
  }
}

Common Mistakes

常见错误

MistakeImpactSolution
Using
user
for role checks
Cache explosion (1 entry per user)Use
user.roles
Using
session
directly
Triggers auto-placeholderUse lazy builder
Missing contextSame cached content for all variationsAdd appropriate context
Too broad contextUnnecessary cache variationsUse most specific context
错误影响解决方案
使用
user
进行角色检查
缓存膨胀(每个用户对应一个缓存条目)使用
user.roles
直接使用
session
触发自动占位符使用lazy builder
遗漏上下文所有变体共享相同缓存内容添加对应的上下文
上下文范围过宽不必要的缓存变体使用最具体的上下文

Auto-Placeholdering

自动占位符机制

These contexts trigger automatic placeholdering in Dynamic Page Cache:
yaml
undefined
以下上下文会在动态页面缓存中触发自动占位符:
yaml
undefined

services.yml - default conditions

services.yml - default conditions

renderer.config: auto_placeholder_conditions: contexts: - 'session' - 'user'

Content with these contexts is replaced with a placeholder and rendered separately.
renderer.config: auto_placeholder_conditions: contexts: - 'session' - 'user'

带有这些上下文的内容会被替换为占位符,单独进行渲染。

Debugging

调试方法

bash
undefined
bash
undefined

Enable debug headers

启用调试头

$settings['http.response.debug_cacheability_headers'] = TRUE;
$settings['http.response.debug_cacheability_headers'] = TRUE;

Check applied contexts

检查已应用的上下文

curl -sI https://site.com/ | grep X-Drupal-Cache-Contexts
curl -sI https://site.com/ | grep X-Drupal-Cache-Contexts

Output: X-Drupal-Cache-Contexts: languages:language_interface theme url.path user.permissions

输出示例:X-Drupal-Cache-Contexts: languages:language_interface theme url.path user.permissions

undefined
undefined