7

I am doing this:

domain.com/route-name/?do-something=1

..which sets a cookie and then redirects to this using a 302 redirect:

domain.com/route-name/

It allows an action to take place regardless of the page viewing (cookie stores a setting for the user).

I am using the default Symfony2 reverse-proxy cache and all is well, but I need to prevent both the above requests from caching.

I am using this to perform the redirect:

// $event being a listener, usually a request listener

$response = new RedirectResponse($url, 302);    
$this->event->setResponse($response);

I've tried things like this but nothing seems to work:

$response->setCache(array('max_age' => 0));
header("Cache-Control: no-cache");

So how do I stop it caching those pages?

user2143356
  • 5,467
  • 19
  • 51
  • 95

2 Answers2

13

You have to make sure you are sending the following headers with the RedirectResponse ( if the GET parameter is set ) AND with your regular Response for the route:

Cache-Control: private, max-age=0, must-revalidate, no-store;

Achieve what you want like this:

$response->setPrivate();
$response->setMaxAge(0);
$response->setSharedMaxAge(0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);

private is important and missing in coma's answer.

The difference is that with Cache-Control: private you are not allowing proxies to cache the data that travels through them.

Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130
  • Thanks for the help. Both answers very similar and both have the same result. This works great at caching the first URL (with the query string), but when it then redirects to the final URL (the domain.com/route-name/ part) that is still cached. It's as though caching headers need to be passed onto the redirected page or something. – user2143356 May 25 '13 at 19:52
  • the domain.com/route-name **/** route has to send the cache-control headers aswell. you do send them with your redirect-reponse AND your route do you ? – Nicolai Fröhlich May 25 '13 at 20:07
  • I've basically added your code inbetween the two lines I listed above. I've also looked at http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/RedirectResponse.html but can't see what else can be done. – user2143356 May 25 '13 at 20:24
  • you need the cache control settings TWICE in your controller action... once for the redirect response and once for your normal response ( whre no redirect happens ). you included both of them? I have updated the answer accordingly. – Nicolai Fröhlich May 25 '13 at 20:44
  • Thanks, I get it now. The problem I'm having is on the second/final request detecting if it was from a redirect. I can't see anything in http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/Request.html which would tell me that. I obviously need something to separate it from a normal user-initiated request. It returns a 200 status code – user2143356 May 25 '13 at 21:48
  • ah okay you want to cache but only in case coming from a redirect forbid caching? then safe a parameter in your session and if present , remove it and output the no-cache headers ! – Nicolai Fröhlich May 25 '13 at 21:54
  • is your problem now solved by my answer ? or shall i add something? otherwise please accept the answer :) – Nicolai Fröhlich May 25 '13 at 23:59
  • Still trying to solve it. Thanks. Whilst I'm setting the cache headers on the 2nd request it still won't clear the cache. – user2143356 May 25 '13 at 23:59
  • where are you haning ? did you try saving the parameter in the session to decide wether to send headers or not ? – Nicolai Fröhlich May 26 '13 at 00:00
  • Got there in the end. Problem with detecting and clearing the session, but all sorted. Any idea about this one: http://stackoverflow.com/questions/16753279/symfony2-reverse-proxy-separating-the-caching-of-the-same-url-based-on-a-cooki – user2143356 May 26 '13 at 00:16
  • I've unaccepted the answer as it's not quite right. The problem is the second request isn't even hitting the server as it's the browser that's caching it. So somehow I need to stop the browser from using its cache (without adding a query param). – user2143356 May 26 '13 at 13:18
  • thats what i told you to do ... send the cache header on redirect (url with get query-parameter ) AND request without query-parameter. now clear your browser cache and the browser will cache none of both. Browser will only cache if header not present ... so make sure you send the no-cache header with every of the two reponses. – Nicolai Fröhlich May 26 '13 at 13:28
  • No problem with clearing browser cache. That's all dealt with (have ensured that all along). Problem is with setting the session and then detecting the set session. Detecting the set session isn't possible because the second request doesn't hit the server. You're right in saying to set headers on second request, but it can't be done by detecting the set session. It must be done at the same time as the header(Location: URL); PHP call. – user2143356 May 26 '13 at 13:38
  • In fact where you mention 'AND with your regular Response for the route:' isn't possible due to it not hitting the server – user2143356 May 26 '13 at 13:39
  • how can it not be hitting the server? user requests url?p=bar... request hits symfony ... symfony responds: DONT CACHE but please redirect my user to to url/ please ( status 301 and no-cache header )... browser is like 'mh okay i won't cache' ... and requests url/ ... requests hits symfony AGAIN ... symfony sends DONT CACHE ( http 200, no-cache ) ... AGAIN ... browser is like 'mkay i wont cache that either' ... and thats what you wanted ... – Nicolai Fröhlich May 26 '13 at 13:50
  • I don't understand any of that, but yes it does not hit the server. The first response hits the server and returns a completely new response (302). The second request is returned from the browser cache. – user2143356 May 26 '13 at 13:53
  • provide a screenshot of your firebug / dev tools network requests and headers please. hit the page two times ( cache cleared before) ... ?pfoo, / , ?p=foo, / ... – Nicolai Fröhlich May 26 '13 at 14:00
  • 1
    I found that if `setSharedMaxAge()` is set, the cache-control ignore the `setPrivate()` directive - headers still returned public. If you think of the purpose of the `s-maxage` directive, this makes sense. – BrynJ Jul 25 '16 at 13:43
  • `setSharedMaxAge` sets the response to public. Do not use `setSharedMaxAge` if you want a private response. – Petter Kjelkenes Nov 06 '18 at 15:12
1

Try this on your response:

$response->headers->addCacheControlDirective('no-cache', true);
$response->headers->addCacheControlDirective('max-age', 0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);

You can use annotations too:

http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/cache.html

And take a look at:

Why both no-cache and no-store should be used in HTTP response?

Community
  • 1
  • 1
coma
  • 16,429
  • 4
  • 51
  • 76
  • Thanks for the help. This and other answer very similar and thanks. Please see other answer for comment as it's not quite doing what I need. Thanks, – user2143356 May 25 '13 at 19:52