HTTP Cache ¶
The nature of rich web applications means that they're dynamic. No matter how efficient your application, each request will always contain more overhead than serving a static file. Usually, that's fine. But when you need your requests to be lightning fast, you need HTTP caching.
Caching on the Shoulders of Giants ¶
With HTTP Caching, you cache the full output of a page (i.e. the response) and bypass your application entirely on subsequent requests. Caching entire responses isn't always possible for highly dynamic sites, or is it? With Edge Side Includes (ESI), you can use the power of HTTP caching on only fragments of your site.
The Symfony cache system is different because it relies on the simplicity and power of the HTTP cache as defined in RFC 7234 - Caching. Instead of reinventing a caching methodology, Symfony embraces the standard that defines basic communication on the Web. Once you understand the fundamental HTTP validation and expiration caching models, you'll be ready to master the Symfony cache system.
Since caching with HTTP isn't unique to Symfony, many articles already exist on the topic. If you're new to HTTP caching, Ryan Tomayko's article Things Caches Do is highly recommended. Another in-depth resource is Mark Nottingham's Cache Tutorial.
Caching with a Gateway Cache ¶
When caching with HTTP, the cache is separated from your application entirely and sits between your application and the client making the request.
The job of the cache is to accept requests from the client and pass them back to your application. The cache will also receive responses back from your application and forward them on to the client. The cache is the "middle-man" of the request-response communication between the client and your application.
Along the way, the cache will store each response that is deemed "cacheable" (See HTTP Cache). If the same resource is requested again, the cache sends the cached response to the client, ignoring your application entirely.
This type of cache is known as an HTTP gateway cache and many exist such as Varnish, Squid in reverse proxy mode, and the Symfony reverse proxy.
Tip
Gateway caches are sometimes referred to as reverse proxy caches, surrogate caches, or even HTTP accelerators.
Symfony Reverse Proxy ¶
Symfony comes with a reverse proxy (i.e. gateway cache) written in PHP. It's not a fully-featured reverse proxy cache like Varnish, but it is a great way to start.
Tip
For details on setting up Varnish, see How to Use Varnish to Speed up my Website.
Use the framework.http_cache
option to enable the proxy for the
prod environment:
-
YAML
YAML
-
XML
XML
-
PHP
PHP
1 2 3 4 |
# config/packages/framework.yaml
when@prod:
framework:
http_cache: true
|
The kernel will immediately act as a reverse proxy: caching responses from your application and returning them to the client.
The proxy has a sensible default configuration, but it can be finely tuned via a set of options.
When in debug mode, Symfony automatically adds an
X-Symfony-Cache
header to the response. You can also use the trace_level
config option and set it to either none
, short
or full
to add this
information.
short
will add the information for the main request only.
It's written in a concise way that makes it easy to record the
information in your server log files. For example, in Apache you can
use %{X-Symfony-Cache}o
in LogFormat
format statements.
This information can be used to extract general information about
cache efficiency of your routes.
Tip
You can change the name of the header used for the trace
information using the trace_header
config option.
Making your Responses HTTP Cacheable ¶
Once you've added a reverse proxy cache (e.g. like the Symfony reverse proxy or Varnish), you're ready to cache your responses. To do that, you need to communicate to your cache which responses are cacheable and for how long. This is done by setting HTTP cache headers on the response.
HTTP specifies four response cache headers that you can set to enable caching:
Cache-Control
キャッシュ制御Expires
期限切れETag
ETagLast-Modified
最終更新日
These four headers are used to help cache your responses via two different models:
- Expiration Caching
Used to cache your entire response for a specific amount of time (e.g. 24 hours).
Simple, but cache invalidation is more difficult.有効期限のキャッシュ特定の時間 (24 時間など) の間、応答全体をキャッシュするために使用されます。単純ですが、キャッシュの無効化はより困難です。
- Validation Caching
More complex: used to cache your response, but allows you to dynamically invalidate
it as soon as your content changes.検証キャッシュより複雑: 応答をキャッシュするために使用されますが、コンテンツが変更されるとすぐに動的に無効にすることができます。
Expiration Caching ¶
The easiest way to cache a response is by caching it for a specific amount of time:
-
Attributes
属性
-
PHP
PHP
1 2 3 4 5 6 7 8 9 |
// src/Controller/BlogController.php
use Symfony\Component\HttpKernel\Attribute\Cache;
// ...
#[Cache(public: true, maxage: 3600, mustRevalidate: true)]
public function index(): Response
{
return $this->render('blog/index.html.twig', []);
}
|
6.2
The #[Cache()]
attribute was introduced in Symfony 6.2.
Thanks to this new code, your HTTP response will have the following header:
1 |
Cache-Control: public, maxage=3600, must-revalidate
|
This tells your HTTP reverse proxy to cache this response for 3600 seconds. If anyone
requests this URL again before 3600 seconds, your application won't be hit at all.
If you're using the Symfony reverse proxy, look at the X-Symfony-Cache
header
for debugging information about cache hits and misses.
Tip
The URI of the request is used as the cache key (unless you vary).
This provides great performance and is simple to use. But, cache invalidation is not supported. If your content change, you'll need to wait until your cache expires for the page to update.
Tip
Actually, you can manually invalidate your cache, but it's not part of the HTTP Caching spec. See Cache Invalidation.
If you need to set cache headers for many different controller actions, check out FOSHttpCacheBundle. It provides a way to define cache headers based on the URL pattern and other request properties.
Finally, for more information about expiration caching, see HTTP Cache Expiration.
Validation Caching ¶
With expiration caching, you say "cache for 3600 seconds!". But, when someone updates cached content, you won't see that content on your site until the cache expires.
If you need to see updated content immediately, you either need to invalidate your cache or use the validation caching model.
For details, see HTTP Cache Validation.
Safe Methods: Only caching GET or HEAD requests ¶
HTTP caching only works for "safe" HTTP methods (like GET and HEAD). This means three things:
- Don't try to cache PUT or DELETE requests. It won't work and with good reason.
These methods are meant to be used when mutating the state of your application
(e.g. deleting a blog post). Caching them would prevent certain requests from hitting
and mutating your application.PUT または DELETE リクエストをキャッシュしようとしないでください。これらのメソッドは、アプリケーションの状態を変更する場合 (ブログ投稿の削除など) に使用することを意図しています。それらをキャッシュすると、特定のリクエストがアプリケーションにヒットして変更されるのを防ぐことができます。
- POST requests are generally considered uncacheable, but they can be cached
when they include explicit freshness information. However, POST caching is not
widely implemented, so you should avoid it if possible.POST リクエストは一般にキャッシュ不可と見なされますが、明示的な鮮度情報が含まれている場合はキャッシュできます。ただし、POST キャッシングは広く実装されているわけではないため、可能であれば使用を避ける必要があります。
- You should never change the state of your application (e.g. update a blog post)
when responding to a GET or HEAD request. If those requests are cached, future
requests may not actually hit your server.GET または HEAD リクエストに応答するときは、アプリケーションの状態を決して変更しないでください (ブログ投稿を更新するなど)。これらのリクエストがキャッシュされている場合、将来のリクエストが実際にサーバーにヒットしない可能性があります。
More Response Methods ¶
The Response class provides many more methods related to the cache. Here are the most useful ones:
1 2 3 4 5 |
// marks the Response stale
$response->expire();
// forces the response to return a proper 304 response with no content
$response->setNotModified();
|
Additionally, most cache-related HTTP headers can be set via the single setCache() method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// use this method to set several cache settings in one call
// (this example lists all the available cache settings)
$response->setCache([
'must_revalidate' => false,
'no_cache' => false,
'no_store' => false,
'no_transform' => false,
'public' => true,
'private' => false,
'proxy_revalidate' => false,
'max_age' => 600,
's_maxage' => 600,
'immutable' => true,
'last_modified' => new \DateTime(),
'etag' => 'abcdef'
]);
|
Tip
All these options are also available when using the #[Cache()]
attribute.
Cache Invalidation ¶
Cache invalidation is not part of the HTTP specification. Still, it can be really useful to delete various HTTP cache entries as soon as some content on your site is updated.
For details, see Cache Invalidation.
Using Edge Side Includes ¶
When pages contain dynamic parts, you may not be able to cache entire pages, but only parts of it. Read Working with Edge Side Includes to find out how to configure different cache strategies for specific parts of your page.
HTTP Caching and User Sessions ¶
Whenever the session is started during a request, Symfony turns the response into a private non-cacheable response. This is the best default behavior to not cache private user information (e.g. a shopping cart, a user profile details, etc.) and expose it to other visitors.
However, even requests making use of the session can be cached under some circumstances. For example, information related to some user group could be cached for all the users belonging to that group. Handling these advanced caching scenarios is out of the scope of Symfony, but they can be solved with the FOSHttpCacheBundle.
In order to disable the default Symfony behavior that makes requests using the session uncacheable, add the following internal header to your response and Symfony won't modify it:
1 2 3 |
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');
|
Summary ¶
Symfony was designed to follow the proven rules of the road: HTTP. Caching is no exception. Mastering the Symfony cache system means becoming familiar with the HTTP cache models and using them effectively. This means that, instead of relying only on Symfony documentation and code examples, you have access to a world of knowledge related to HTTP caching and gateway caches such as Varnish.
Learn more ¶
- Cache Invalidationキャッシュの無効化
- Varying the Response for HTTP CacheHTTP キャッシュに対する応答の変更
- Working with Edge Side Includesエッジ サイド インクルードの操作
- HTTP Cache ExpirationHTTP キャッシュの有効期限
- Working with Server Side Includesサーバーサイドインクルードの操作
- HTTP Cache ValidationHTTP キャッシュの検証
- How to Use Varnish to Speed up my Websiteワニスを使用してウェブサイトを高速化する方法