You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Drupal 8站点股票行情块单独排除缓存的实现问题求助

解决Drupal 8中单独排除股票行情块缓存的问题

你遇到的问题很典型:整页缓存(Drupal自带的页面缓存+Varnish)会把所有内容包括你的股票行情块一起缓存,单独在预处理钩子中设置max-age根本不会生效——因为整页缓存优先级更高,块的缓存规则被忽略了。下面给你两种可行的解决方案,按需选择:

方案一:使用ESI(Edge Side Includes)推荐,适合服务器端渲染+SEO友好

ESI是Varnish支持的一种技术,可以让整页缓存时,单独请求指定块的内容,绕过整页缓存规则。这样你的股票行情块就能独立控制缓存时长,不影响页面其他静态内容。

步骤1:开启Drupal的ESI支持

  1. 进入Drupal后台,依次点击 配置 → 性能
  2. 找到「缓存高级设置」,勾选「允许ESI」,保存配置

步骤2:修正你的预处理钩子代码

之前的代码缺少ESI开启的关键配置,同时要确保块的标识判断正确建议临时用kint($vars)打印变量,确认derivative_plugin_id的准确值:

function mytheme_preprocess_block(&$vars) {
  // 确认块的标识是否正确,可临时用kint($vars)查看
  if($vars['derivative_plugin_id'] == 'stocktickerblock') {
    // 开启ESI,让Varnish单独处理这个块的请求
    $vars['#esi'] = TRUE;
    // 设置块的缓存时长为5分钟(300秒)
    $vars['#cache']['max-age'] = 300;
    // 添加缓存标签,数据库更新时可主动清除块缓存
    $vars['#cache']['tags'] = ['stock_ticker_data'];
    // 该块不依赖用户/语言等上下文,清空上下文列表
    $vars['#cache']['contexts'] = [];
  }
}

步骤3:配置Varnish支持ESI

修改你的Varnish配置文件(通常是default.vcl),添加以下规则:

  • vcl_recv函数中:
if (req.http.X-ESI == '1') {
  set req.http.Surrogate-Capability = "abc=ESI/1.0";
}
  • vcl_backend_response函数中:
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
  unset beresp.http.Surrogate-Control;
  set beresp.do_esi = true;
}

修改后重启Varnish服务。

步骤4:数据库更新时主动清缓存

在你的数据库更新脚本中,添加一行代码清除股票行情块的缓存标签,这样数据更新后能立即刷新块内容:

\Drupal\Core\Cache\Cache::invalidateTags(['stock_ticker_data']);

方案二:AJAX动态加载块内容适合无法修改Varnish配置的场景

如果没法调整Varnish配置,你可以用前端AJAX定时请求最新的行情数据,完全绕过整页缓存。

步骤1:修改块的模板文件

找到股票行情块的模板(比如block--stocktickerblock.html.twig),替换内容为:

<div id="stock-ticker-container">
  {# 初始加载的静态内容 #}
  {{ content }}
</div>

<script>
  // 每隔5分钟(300000毫秒)刷新一次行情
  setInterval(function() {
    fetch('/stock-ticker/ajax')
      .then(response => response.text())
      .then(data => {
        document.getElementById('stock-ticker-container').innerHTML = data;
      });
  }, 300000);
</script>

步骤2:创建AJAX路由和控制器

  1. 在你的自定义模块的routing.yml中添加路由:
stock_ticker.ajax:
  path: '/stock-ticker/ajax'
  defaults:
    _controller: '\Drupal\mymodule\Controller\StockTickerController::ajaxRender'
    _title: 'Stock Ticker AJAX'
  requirements:
    _access: 'TRUE'
  1. 创建控制器类,返回最新的行情数据:
namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Cache\CacheableResponse;

class StockTickerController extends ControllerBase {

  public function ajaxRender() {
    // 从数据库获取最新行情数据
    $stock_data = $this->fetchStockData();
    
    $build = [
      '#theme' => 'stock_ticker', // 自定义模板渲染数据
      '#data' => $stock_data,
      '#cache' => [
        'max-age' => 0, // 禁止缓存AJAX请求结果
        'tags' => ['stock_ticker_data'],
      ],
    ];
    
    $response = new CacheableResponse(\Drupal::service('renderer')->renderRoot($build));
    $response->getCacheableMetadata()->addCacheTags(['stock_ticker_data']);
    return $response;
  }

  private function fetchStockData() {
    // 这里写你的数据库查询逻辑
    $database = \Drupal::database();
    return $database->query('SELECT * FROM stock_data ORDER BY updated_at DESC LIMIT 1')->fetchAssoc();
  }
}

两种方案对比

方案优点缺点
ESI服务器端渲染,SEO友好;不依赖前端JS需要修改Varnish配置;对服务器配置有要求
AJAX无需调整Varnish;实现简单初始加载可能有延迟;JS禁用时无法更新内容

内容的提问来源于stack exchange,提问作者pburgh

火山引擎 最新活动