webfactory / http-cache-bundle
Symfony 扩展包,通过最后修改时间头简化 HTTP 缓存验证
Requires
- php: ^8.1
- symfony/config: ^5.0 | ^6.0 | ^7.0
- symfony/dependency-injection: ^5.0 | ^6.0 | ^7.0
- symfony/deprecation-contracts: ^2.0|^3.0
- symfony/http-foundation: ^5.0 | ^6.0 | ^7.0
- symfony/http-kernel: ^5.3 | ^6.0 | ^7.0
Requires (Dev)
- phpunit/phpunit: ^9.6
- symfony/phpunit-bridge: ^6.0 | ^7.0
Suggests
- webfactory/wfdmeta-bundle: Invalidate caches based on meta data tracked with wfDynamic
This package is auto-updated.
Last update: 2024-08-27 07:37:30 UTC
README
WebfactoryHttpCacheBundle
是一个 Symfony 扩展包,它提供了一个比 symfony/http-kernel 包中的 #[Cache]
属性 更强大的功能,用于通过最后修改时间头进行 HTTP 缓存验证。
#[ReplaceWithNotModifiedResponse]
属性允许您为请求页面的每个底层资源编写小的 LastModifiedDeterminators
。它们可以自由地重复使用和组合,甚至可以定义为服务。
考虑以下控制器代码
<?php // ... use Webfactory\HttpCacheBundle\NotModified\Attribute\ReplaceWithNotModifiedResponse; class MyController { // Routing etc. configuration skipped for brevity #[ReplaceWithNotModifiedResponse(["@app_caching_post", "@app_caching_latest_posts"])] public function indexAction(Post $post): Response { // your code // won't be called in case of a 304 } }
当 Symfony 的路由选择此控制器动作时,所有 LastModifiedDeterminator
都会被调用以返回它们各自的上次修改日期。
在这种情况下,两个 LastModifiedDeterminators 都配置为服务:@app_caching_post
和 @app_caching_latest_posts
。第一个返回请求 $post
的更新日期,第二个可能使用从 DI 容器注入的 PostRepository 返回最后更新日期的 x 条最新帖子。
#[ReplaceWithNotModifiedResponse]
将所有 LastModifiedDeterminators
的日期组合起来,以确定整个页面的最后修改日期。最后,如果请求包含适当的 if-not-modified-since
头,则跳过控制器动作的执行,并返回一个带有 "304 Not Modified" 状态码的空响应。如果您的 LastModifiedDeterminators
很快,这可以大大提高您的性能。
我们喜欢 LastModifiedDeterminators
的地方在于,它们鼓励将关注点分离得很好,并将任务封装成易于理解、可重用和单元测试的小单元。
注意: #[ReplaceWithNotModifiedResponse]
不会更改或添加 Cache-Control
头设置。因此,默认情况下,您的响应将保持 private
,并且仅在浏览器缓存中结束。如果您希望它被保留在代理缓存(如 Varnish 或 Symfony Http Cache)中,您可以添加 #[Cache(smaxage: 0)]
。这将使响应变为 public
,但也需要在每次请求时进行重新验证,因为响应总是被认为是过时的。有关 Symfony 的 HTTP 缓存的更多信息,请参阅 Symonfy 的 HTTP 缓存。
用法
选择一个您可能希望替换为 304 Not Modified 响应的控制器动作。为不同的底层资源编写一个 LastModifiedDeterminator
,实现 Webfactory\HttpCacheBundle\NotModified\LastModifiedDeterminator
接口。
<?php // src/Caching/PostsLastModifiedDeterminator.php namespace App\Caching; use App\Entity\PostRepository; use Symfony\Component\HttpFoundation\Request; use Webfactory\HttpCacheBundle\NotModified\LastModifiedDeterminator; /** * Returns the publishing date of the latest posts. */ final class PostsLastModifiedDeterminator implements LastModifiedDeterminator { public function __construct( private readonly BlogPostRepository $blogPostRepository, ) { public function getLastModified(Request $request): ?\DateTime { $post = $this->blogPostRepository->findLatest(); return $post?->getPublishingDate(); } }
您可以在 getLastModified
中使用 $request
,例如获取路由参数,这在您在请求的 URL 中编写一些过滤器时是必要的。
如果您的 LastModifiedDeterminator 有依赖项,您希望注入,则将其配置为服务。
然后,将 #[ReplaceWithNotModifiedResponse]
属性添加到所选控制器方法中,并使用您的 LastModifiedDeterminators 参数化它
<?php namespace src\Controller; use Symfony\Component\HttpFoundation\Response; use Webfactory\HttpCacheBundle\NotModified\Attribute\ReplaceWithNotModifiedResponse; final class MyController { #[ReplaceWithNotModifiedResponse([...])] public function indexAction() { // ... return new Response(...); } }
添加 LastModifiedDeterminator 的最简单形式是传递其完全限定的类名
#[ReplaceWithNotModifiedResponse([\App\Caching\MySimpleLastModifiedDeterminator::class])]
如果您的 LastModifiedDeterminator 需要简单的构造函数参数,您可以将其作为数组传递
#[ReplaceWithNotModifiedResponse([\App\Caching\MyLastModifiedDeterminator::class => ["key1" => 1, "key2" => ["*"]]])]
这将传递数组 ['key1' => 1, 'key2' => ['*']] 作为 MyLastModifiedDeterminator 的构造函数参数。
如果您的 LastModifiedDeterminator 有更复杂的依赖项,您可以将其定义为服务,例如。
yaml // services.yml services: app_caching_latest_posts: class: App\Caching\PostsLastModifiedDeterminator arguments: - @repository_post
并将服务名称放入属性中
#[ReplaceWithNotModifiedResponse(["@app_caching_latest_posts"])]
要组合多个LastModifiedDeterminators,只需将它们全部添加到属性中
#[ReplaceWithNotModifiedResponse([
"@app_caching_latest_posts",
\App\Caching\MySimpleLastModifiedDeterminator::class,
[\App\Caching\MyLastModifiedDeterminator::class => ["key1" = 1, "key2" => ["*"]]
])]
最新的最后修改日期决定了响应的最后修改日期。
版权信息、著作权和许可证
本捆绑包由德国波恩的webfactory GmbH启动。
版权所有 2018-2024 德国波恩webfactory GmbH。代码在MIT许可证下发布。