Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel response Cache-Control headers always containing 'no-cache'

For some reason Laravel seems to be manipulating the response headers 'Cache-Control' on the very last moment. I want to make browser caching possible.

class TestController extends Controller
{

    public function getTest()
    {
        $response = new \Illuminate\Http\Response('test', 200, array(
            'Cache-Control' => 'max-age='.(config('imagecache.lifetime')*60).', public',
            'Content-Length' => strlen('test'),
        ));

        $response->setLastModified(new \DateTime('now'));
        $response->setExpires(\Carbon\Carbon::now()->addMinutes(config('imagecache.lifetime')));

        return $response;
     }
}

Even when I use a 'after-middleware' and die and dump the response, I still get this, what seems to be right to me.

Response {#625 ▼
  +original: "test"
  +exception: null
  +headers: ResponseHeaderBag {#626 ▼
    #computedCacheControl: array:2 [▼
      "max-age" => "2592000"
      "public" => true
    ]
    #cookies: []
    #headerNames: array:5 [▶]
    #headers: array:5 [▼
      "cache-control" => array:1 [▼
        0 => "max-age=2592000, public"
      ]
      "content-length" => array:1 [▼
        0 => 4
      ]
      "date" => array:1 [▶]
      "last-modified" => array:1 [▼
        0 => "Sun, 16 Aug 2015 15:42:08 GMT"
      ]
      "expires" => array:1 [▶]
    ]
    #cacheControl: array:2 [▼
      "max-age" => "2592000"
      "public" => true
    ]
  }
  #content: "test"
  #version: "1.0"
  #statusCode: 200
  #statusText: "OK"
  #charset: null
}

The method $response->isCacheable() als returns true. But when I receive the response, Firebug shows the following:

Cache-Control   
no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection  
Keep-Alive
Content-Type    
text/html
Date    
Sun, 16 Aug 2015 15:42:08 GMT
Expires 
Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive  
timeout=5, max=98
Pragma  
no-cache
Server  
Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.15
Transfer-Encoding   
chunked
X-Powered-By    
PHP/5.5.15

I use xampp, but on this same server when I just load an html-page (no Laravel/PHP), it does not send these Cache-Control headers.

How can I achieve that the browser does not receive the Cache-Control headers "no-store, no-cache" when I set the last-modified and expires headers?

Thanks!

like image 738
Riesjart Avatar asked Sep 02 '15 18:09

Riesjart


People also ask

What happens if there is no Cache-Control header?

Without the cache control header the browser requests the resource every time it loads a new(?) page.

What does Cache-Control no cache mean?

Cache-Control: No-Cache The no-cache directive means that a browser may cache a response, but must first submit a validation request to an origin server.

What should you add to a Cache-Control response header?

private. The private response directive indicates that the response can be stored only in a private cache (e.g. local caches in browsers). You should add the private directive for user-personalized content, especially for responses received after login and for sessions managed via cookies.

Which response header tells the client and intermediaries that the response is not to be cached?

cache-control: no-store A response with a 'no-store' directive cannot be cached anywhere, ever. This means that every time a user requests this data, a request must be sent to the origin server for a fresh copy.


2 Answers

I believe your phantom cache-control headers are coming from PHP.

http://php.net/manual/en/function.session-cache-limiter.php

when php.ini has session.cache_limiter set to nocache (default), PHP sets the following headers:

Expires: Thu, 19 Nov 1981 08:52:00 GMT 
Cache-Control: no-store,no-cache, must-revalidate, post-check=0, pre-check=0 
Pragma: no-cache

I have been struggling with cache-control in laravel on apache for a few days now: I found that setting the headers within laravel simply appended them on to the headers set by php.ini. I tried setting up some rules in apache.conf in order to allow caching of .js and .css files that were being accessed via laravel while preventing the caching of requests to .php files, but these rules failed as apache will see any file being served via laravel as a .php file (because it is being accessed via index.php).

In the end I settled for setting session.cache_limiter to '' in php.ini (thereby skipping PHPs handling of cache headers), and adding the following to filters.php in app:after()

     /*
     * Custom cache headers for js and css files
     */
    if ($request->is('*.js') || $request->is('*.css')){
        $response->header("pragma", "private");
        $response->header("Cache-Control", " private, max-age=86400");
    } else {
        $response->header("pragma", "no-cache");
        $response->header("Cache-Control", "no-store,no-cache, must-revalidate, post-check=0, pre-check=0");
    }
like image 119
Geoff Salmon Avatar answered Sep 19 '22 04:09

Geoff Salmon


Although I do not know your exact configuration, I would assume that this is due to your Apache configuration, as header values can be overwritten there.

Have a look through all Apache configuration files and look out for lines starting with Header Set Cache-Control, e.g. Header Set Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"

Probably such a directive is set to affect only your PHP files, which would be the reason why other files are delivered with other headers.

However: Watch out when changing this. Maybe you would want this to be set for security reasons. Consider the problems with caching dynamic, authenticated content by proxies (link for detail)

like image 44
Jan D Avatar answered Sep 18 '22 04:09

Jan D