barryvdh/laravel-httpcache
Adds HTTP caching to Laravel using Symfony HttpCache. Supports reverse proxy-style caching, cache invalidation, and ESI, helping you speed up responses while keeping dynamic content fresh with simple middleware and configuration.
Installation:
composer require barryvdh/laravel-httpcache
Publish the config file (if needed):
php artisan vendor:publish --provider="Barryvdh\HttpCache\ServiceProvider"
First Use Case: Cache a route response for 10 minutes:
Route::get('/cached-page', function () {
return response()->view('cached-view');
})->middleware('http_cache');
Key Config:
Check .env for:
HTTP_CACHE_DRIVER=file # or 'redis', 'memcached', etc.
HTTP_CACHE_DEFAULT_TTL=3600 # Default TTL in seconds
Verify: Access the cached route and inspect headers:
Cache-Control: public, max-age=600
X-Cache: HIT
Route-Level Caching:
Route::get('/products', ProductController::class)
->middleware('http_cache:public, max-age=3600'); // Custom headers
Controller-Level Caching:
public function index()
{
return Cache::remember('products_list', now()->addMinutes(10), function () {
return Product::all();
});
}
Combine with middleware for HTTP-level caching.
Dynamic TTL:
Route::get('/user/{id}', function ($id) {
return response()->json(User::find($id));
})->middleware('http_cache:public, max-age=' . config('http_cache.user_ttl'));
Conditional Caching:
Route::get('/dashboard', function () {
if (auth()->check()) {
return response()->view('dashboard');
}
return response()->view('guest-dashboard');
})->middleware('http_cache:private, must-revalidate');
With API Responses:
Route::get('/api/data', function () {
return response()->json(['data' => 'cached']);
})->middleware('http_cache:public, s-maxage=86400, must-revalidate');
Cache Invalidation:
// Invalidate a specific route
Cache::forget('http_cache:GET:/products');
// Invalidate all cached routes
Cache::flush();
Custom Cache Store:
Extend the Barryvdh\HttpCache\CacheStore class to integrate with custom storage backends.
Middleware Chaining:
Route::get('/secure-cached', function () {
return response()->view('secure-page');
})->middleware(['auth', 'http_cache:private, max-age=300']);
Cache Headers Conflict:
Cache-Control headers are set manually in the response, they override the middleware.response()->header() after the middleware or adjust middleware priority.TTL Misconfiguration:
http_cache.options.default_ttl) may not apply if headers are explicitly set.'default_ttl' => 3600, // 1 hour in seconds
Private Cache Issues:
Cache-Control: private) may not work as expected with shared proxies.must-revalidate or no-store for sensitive data.Cache Store Quirks:
file driver) may cause race conditions in high-traffic apps.redis or memcached for production.Middleware Order:
http_cache after authentication middleware to avoid caching unauthorized responses.app/Http/Kernel.php:
'web' => [
\App\Http\Middleware\Authenticate::class,
\Barryvdh\HttpCache\Middleware\HttpCache::class,
],
Check Cache Status:
Inspect headers for X-Cache:
X-Cache: MISS # Not cached
X-Cache: HIT # Cached
Log Cache Events: Enable debug mode in config:
'debug' => env('HTTP_CACHE_DEBUG', false),
Clear Cache Manually:
php artisan cache:clear
php artisan http-cache:clear
Test Locally:
Use max-age=10 for quick testing:
->middleware('http_cache:public, max-age=10')
Custom Cache Key: Override the cache key logic in a service provider:
HttpCache::extend(function ($request) {
return 'custom_key_' . $request->path();
});
Event Listeners: Listen for cache hits/misses:
HttpCache::listen(function ($event) {
Log::info('Cache event: ' . $event->type, $event->data);
});
Vary Headers:
Support custom Vary headers for dynamic content:
->middleware('http_cache:public, max-age=3600, vary=Accept-Language')
Conditional Logic: Skip caching for specific routes:
if (request()->has('nocache')) {
return response()->view('dynamic-page');
}
Route::get('/dynamic', function () {
return response()->view('dynamic-page');
})->middleware('http_cache:skip_if=nocache');
How can I help you explore Laravel packages today?