terminal42/header-replay-bundle

此软件包已废弃,不再维护。未建议替代包。

发送用于用户上下文头部的预检请求,并重新播放以支持反向代理。

安装次数: 289,360

依赖: 0

建议者: 0

安全: 0

星标: 8

关注者: 4

分支: 0

开放问题: 0

类型:symfony-bundle

1.5.3 2018-10-18 12:10 UTC

This package is auto-updated.

Last update: 2022-07-15 21:09:47 UTC


README

这是什么?

缓存是任何应用程序非常重要但也很困难的任务。反向代理帮助我们维护在(或在前端)您的web服务器上的共享缓存。它们将根据您设置的缓存头(如Cache-Control等)缓存您应用程序的响应。缓存条目始终与某个URI相关。然而,您会发现自己在尝试为同一URI拥有不同的缓存条目(也在这里考虑ESI请求)。这就是Vary头发挥作用的地方。通过设置Vary: <header-name>,您可以告诉反向代理为同一URI添加多个缓存条目,实际上通过不仅使用URI还包括Vary头扩展其内部标识符。

这很好,但很多东西——尤其是在PHP应用程序中——与PHP会话绑定,因此包含PHPSESSIDcookie的Cookie头。现在,如果您想根据会话的一部分来Vary,则需要发送一个Vary: Cookie响应,这基本上扼杀了代理的全部意义,因为两个用户不会拥有相同的Cookie值,对吧?

我们需要做的是将与我们PHP会话相关的数据拆分成多个头,这样我们就可以单独对它们进行Vary。让我们通过一个例子来探讨这个问题。想象一下一些没有响应式布局的旧应用程序,您有一些桌面和移动版本,您可以在这些版本之间切换,而应用程序会存储您在会话中喜欢的版本。现在,由于移动设备和桌面上的内容不同,我们需要单独缓存这些条目。所以,在响应上使用Page-Layout: mobilePage-Layout: desktop以及相应的Vary: Page-Layout头可以解决这个问题。但是,没有浏览器会在初始页面查看时发送您Page-Layout: mobile头,因为它从哪里知道,反向代理因此只会考虑您的一种页面布局。太糟糕了!

当然,有解决这个问题的方法。我称之为“预检请求”,但我还没有找到它的明确定义,但概念很简单

Diagram supporting the explanation that follows in text form

  1. 客户端向服务器发送请求。
  2. 代理拦截请求以尝试从缓存中提供内容。
  3. 根据某些条件(通常是CookieAuthorization头),代理执行对真实应用的“预检请求”。
  4. 真实应用注意到它只是一个“预检请求”,并以“重新播放头”(在我们的例子中为Page-Layout: <基于会话的值>)进行回复。
  5. 代理“重新播放”预检请求的头,并重新开始。
  6. 现在,代理再次检查内部缓存,如果缓存条目想要在Page-Layout上进行Vary,则正确地为同一URI提供不同版本。

您可以在位于此bundle之上的FOSHttpCacheBundle的文档中找到更多关于此概念的信息。

然而,FOSHttpCacheBundle 仅处理“用户上下文”这一个特定用例的过程。对于 FOSHttpCacheBundle,始终只有一个头信息,即 User-Context-Hash。当然,您可以将 Page-Layout 的值包含在这个哈希中,并且可以为每个页面布局实现单独的缓存条目。然而,这种方法的一个缺点是,它再次将多个来源的信息包含在一个头信息中。记得我们说过 Vary: Cookie 并不是很有帮助,因为没有人会共享相同的 Cookie 头信息值吗?当然,这里的情况并不完全相同,因为您仍然会有很多匹配项,但规则很简单。

您在同一头信息中包含的信息越多,您想要 Vary 的缓存命中就越少。

当您处理大量的 ESI 请求,并且您的页面由许多不同信息 Vary 的小片段组成时,这一点尤其有趣。现在想象一下,您有 10 个片段,其中只有 1 个基于用户权限(User-Context-Hash)变化,而其他 9 个仅基于 Page-Layout 变化。如果您将所有信息包含在同一个哈希中,那么这 9 个片段就不会根据用户权限共享,尽管它们完全可以共享!

这就是这个包介入的地方。它允许您轻松注册事件监听器,并自动为 Symfony HttpCache 处理它们。不幸的是,对于 Varnish,仍然需要手动配置,我们将在后面讨论。

安装

步骤 1:下载包

打开命令行,进入您的项目目录,并执行以下命令以下载此包的最新稳定版本

$ composer require terminal42/header-replay-bundle "^1.0" php-http/guzzle6-adapter "^1.0.0"

header-replay-bundle 位于 friendsofsymfony/http-cache-bundle 之上,该包需要虚拟包 php-http/client-implementation。您可以使用任何喜欢的客户端实现,但您必须要求一个,这就是为什么在这个例子中我们使用了 php-http/guzzle6-adapter。您可以在这里了解更多关于 HTTPlug 的信息。

此命令需要您全局安装 Composer,如 Composer 文档的安装章节中所述。

步骤 2:启用包

然后,通过将其添加到项目 app/AppKernel.php 文件中注册的包列表中来启用该包。

<?php
// app/AppKernel.php

// ...
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
            // ...

            new Terminal42\HeaderReplay\HeaderReplayBundle(),
        );

        // ...
    }

    // ...
}

配置

您会喜欢这一点。此包是一个零配置包,因此您不需要做任何事情。

使用方法

  1. 注册应该在预请求上重新播放头信息的事件监听器。以下是一些介绍中关于 Page-Layout 的示例代码
services:
    app.listener.header_replay.page_layout:
        class: AppBundle\EventListener\HeaderReplay\PageLayoutListener
        tags:
            - { name: kernel.event_listener, event: terminal42.header_replay, method: onReplay }
<?php

use Terminal42\HeaderReplay\Event\HeaderReplayEvent;

class PageLayoutListener
{
    public function onReplay(HeaderReplayEvent $event)
    {
        $request = $event->getRequest();
        
        if (null !== $request->getSession() && $request->getSession()->has('page.layout')) {
             $headers = $event->getHeaders();
             $headers->set('Page-Layout', $request->getSession()->get('page.layout'));
        }
    }
}

就是这样,您的 Page-Layout 头信息现在将自动添加到预请求中,并且您可以在响应中对其 Vary。请记住查看有关“代理配置”的章节,看看是否还需要做更多的事情。

顺便说一下:如果您在某些情况下需要完全绕过反向代理,请将 T42-Force-No-Cache: true 头信息添加到响应中(更好的方法是使用类常量 HeaderReplayListener::FORCE_NO_CACHE_HEADER_NAME),就这样。不过,反向代理必须支持这一点!

代理配置

Symfony HttpCache

对于Symfony HttpCache,您可以使用EventDispatchingInterface并实现CacheInvalidation接口。您只需要注册此bundle提供的HeaderReplaySubscriber,其他配置将自动生效

<?php

use FOS\HttpCache\SymfonyCache\CacheInvalidation;
use FOS\HttpCache\SymfonyCache\EventDispatchingHttpCache;
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Terminal42\HeaderReplay\SymfonyCache\HeaderReplaySubscriber;

class AppCache extends HttpCache implements CacheInvalidation
{
    use EventDispatchingHttpCache;

    public function __construct(HttpKernelInterface $kernel, $cacheDir = null)
    {
        parent::__construct($kernel, $cacheDir);
        $this->addSubscriber(new HeaderReplaySubscriber());
    }

    /**
     * {@inheritdoc}
     */
    public function fetch(Request $request, $catch = false)
    {
        return parent::fetch($request, $catch);
    }
}

默认情况下,HeaderReplaySubscriber会检查AuthorizationCookie头。您可以通过向构造函数传递正确的$options来调整此设置

<?php
$subscriber = new HeaderReplaySubscriber(['user_context_headers' => ['My-Header']]);

对于Cookie的特殊情况,如果您知道某些cookie的前置请求是无效的,您也可以忽略这些cookie。此选项接受一个正则表达式数组。例如,如果您想忽略名为Foobar的cookie,请看下面的示例

<?php
$subscriber = new HeaderReplaySubscriber([
    'ignore_cookies' => ['/^Foobar$/']
]);

Varnish

待办事项:请帮助改进文档。