Is it fine if first response is private with AppCache (Symfony2)?

CachingSymfonyCache ControlHttp Caching

Caching Problem Overview


I'm trying to use http caching. In my controller I'm setting a response as follows:

$response->setPublic();
$response->setMaxAge(120);
$response->setSharedMaxAge(120);
$response->setLastModified($lastModifiedAt);

dev mode

In dev environment first response is a 200 with following headers:

cache-control:max-age=120, public, s-maxage=120
last-modified:Wed, 29 Feb 2012 19:00:00 GMT

For next 2 minutes every response is a 304 with following headers:

cache-control:max-age=120, public, s-maxage=120

This is basically what I expect it to be.

prod mode

In prod mode response headers are different. Note that in app.php I wrap the kernel in AppCache.

First response is a 200 with following headers:

cache-control:must-revalidate, no-cache, private
last-modified:Thu, 01 Mar 2012 11:17:35 GMT

So it's a private no-cache response.

Every next request is pretty much what I'd expect it to be; a 304 with following headers:

cache-control:max-age=120, public, s-maxage=120

Should I worry about it? Is it an expected behaviour?

What will happen if I put Varnish or Akamai server in front of it?

I did a bit of debugging and I figured that response is private because of last-modified header. HttpCache kernel uses EsiResponseCacheStrategy to update the cached response (HttpCache::handle() method).

if (HttpKernelInterface::MASTER_REQUEST === $type) {
    $this->esiCacheStrategy->update($response);
}

EsiResponseCacheStrategy turns a response into non cacheable if it uses either Last-Response or ETag (EsiResponseCacheStrategy::add() method):

if ($response->isValidateable()) {
    $this->cacheable = false;
} else {
    // ... 
}

Response::isValidateable() returns true if Last-Response or ETag header is present.

It results in overwriting the Cache-Control header (EsiResponseCacheStrategy::update() method):

if (!$this->cacheable) {
    $response->headers->set('Cache-Control', 'no-cache, must-revalidate');

    return;
}

I asked this question on Symfony2 user group but I didn't get an answer so far: https://groups.google.com/d/topic/symfony2/6lpln11POq8/discussion

Update.

Since I no longer have access to the original code I tried to reproduce the scenario with the latest Symfony standard edition.

Response headers are more consistent now, but still seem to be wrong.

As soon as I set a Last-Modified header on the response, the first response made by a browser has a:

Cache-Control:must-revalidate, no-cache, private

Second response has an expected:

Cache-Control:max-age=120, public, s-maxage=120

If I avoid sending If-Modified-Since header, every request returns must-revalidate, no-cache, private.

It doesn't matter if the request was made in prod or dev environment anymore.

Caching Solutions


Solution 1 - Caching

I have faced same problem. I had to supply 'public' headers my cdn. By default when gateway caching is enabled in prod mode, it returns 200 OK with private, nocache must validate headers.

I solved problem this way.

In app.php, before I send response to user ($respond->send), I have overwritten the cache control header to blank and set cache headers to public and max age(some value).

//code snippet from app.php

    $response = $kernel->handle($request);
    $response->headers->set('Cache-Control', '');
    $response->setPublic();
    $response->setMaxAge(86400);
    $response->send();        

Solution 2 - Caching

The behavior you experience is intended. Symfony2 Docs explicitly describe the situations when private and public are used, default being private.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJakub ZalasView Question on Stackoverflow
Solution 1 - CachingsrikanthsatturiView Answer on Stackoverflow
Solution 2 - CachingUdanView Answer on Stackoverflow