Laravel 5 how to set Cache-Control HTTP header globally?

For people that seek a way to write less code, here is another way you can add headers to a response without extra steps.

In the example above, I created a middleware to prevent routes from being cached in the end user browser.

<?php

class DisableRouteCache
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request)->withHeaders([
            "Pragma" => "no-cache",
            "Expires" => "Fri, 01 Jan 1990 00:00:00 GMT",
            "Cache-Control" => "no-cache, must-revalidate, no-store, max-age=0, private",
        ]);
    }
}

Source: Attaching Headers To Responses


Laravel 5.6+

There's no longer any need to add your own custom middleware.

The SetCacheHeaders middleware comes out of the box with Laravel, aliased as cache.headers

The nice thing about this Middleware is that it only applies to GET and HEAD requests - it will not cache POST or PUT requests since you almost never want to do that.

You can apply this globally easily by updating your RouteServiceProvider:

protected function mapWebRoutes()
{
    Route::middleware('web')
        ->middleware('cache.headers:private;max_age=3600') // added this line
        ->namespace($this->namespace)
        ->group(base_path('routes/web.php'));
}

protected function mapApiRoutes()
{
    Route::prefix('api')
        ->middleware('api')
        ->middleware('cache.headers:private;max_age=3600') // added this line
        ->namespace($this->namespace)
        ->group(base_path('routes/api.php'));
}

I don't recommend that though. Instead, as with any middleware, you can easily apply to specific endpoints, groups, or within the controller itself, e.g.:

Route::middleware('cache.headers:private;max_age=3600')->group(function() {
    Route::get('cache-for-an-hour', 'MyController@cachedMethod');
    Route::get('another-route', 'MyController@alsoCached');
    Route::get('third-route', 'MyController@alsoAlsoCached');
});

Note that the options are separated by semicolon not comma, and hyphens are replaced by underscores. Also, Symfony only supports a limited number of options:

'etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public', 'immutable'

In other words you can't simply copy and paste a standard Cache-Control header value, you will need to update the formatting:

CacheControl format:       private, no-cache, max-age=3600
  ->
Laravel/Symfony format:    private;max_age=3600

Laravel 5.5 <

You can have a global middleware for that. something like:

<?php

namespace App\Http\Middleware;

use Closure;

class CacheControl
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        $response->header('Cache-Control', 'no-cache, must-revalidate');
        // Or whatever you want it to be:
        // $response->header('Cache-Control', 'max-age=100');

        return $response;
    }
}

then just register this as a global middleware in the Kernel file:

protected $middleware = [
    ....
    \App\Http\Middleware\CacheControl::class
];