Response Caching with Laravel 5

Caching is a great way to speed up an application. You can cache views, queries, variables, and tons of other things very easily, but what if you want to cache an entire response?

There are a few different places we could cache a response, in the controller is where I see it done most of the time, but I wanted a more general-use method of caching a response. A great way to do it is in a middleware class.

Our middleware needs to do two things:

  1. Check if our response has been cached, and if it has then return it
  2. If it has not been cached, cache it for the next request

For the first requirement, I’ll use the standard handle()  method you see in most middleware

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    $key = $this->generateKey($request->fullUrl());
    if (Cache::has($key)) {
        // you can also run some cache invalidating logic here if needed
        return response(Cache::get($key));
    }
    return $next($request);
}

We need some sort of unique key for our cached response, so I decided to take the full URL and run it through a simple function to generate a slugged string of the incoming URL

protected function generateKey($url)
{
    return 'response_' . str_slug($url);
}

For the second requirement we can use terminate() . From the docs

If you define a terminate method on your middleware, it will automatically be called after the response is sent to the browser.

So after a response has been sent to the browser, we’ll get that response back and then we can cache it.

/**
 * Handle caching of a request if it doesn't already exist
 */
public function terminate($request, $response)
{
    $key = $this->generateKey($request->fullUrl());
    // if the cache key doesn't exist then we store the entire response
    if (!Cache::has($key)) {
        // cache for 24 hours
        Cache::put($key, $response->getContent(), 1440);
    }
}

Here I’m storing the response for 24 hours, but you can raise or lower that depending on your needs.

Full middleware

<?php

namespace App\Http\Middleware;

use Closure;
use Cache;

class CacheResponse
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        $key = $this->generateKey($request->fullUrl());

        if (Cache::has($key)) {
            return response(Cache::get($key));
        }

        return $next($request);
    }

    /**
     * Handle caching of a request if it doesn't already exist
     */
    public function terminate($request, $response)
    {
        $key = $this->generateKey($request->fullUrl());

        // if the cache key doesn't exist then we store the whole response
        if (!Cache::has($key)) {
            // cache for 24 hours
            Cache::put($key, $response->getContent(), 1440);
        }
    }

    protected function generateKey($url)
    {
        return 'response_' . str_slug($url);
    }
}

Now we need to register our middleware in app/Http/Kernel.php  which you can do by adding our new class to the $routeMiddleware  array

'cacheroute' => \App\Http\Middleware\CacheResponse::class,

And finally, add the middleware to any routes that you want to cache

Route::get('/', function () {
    return view('welcome');
})->middleware('cacheroute');

And now you have simple middleware that you can use to cache any of your responses.

One thought on “Response Caching with Laravel 5

  1. You can use static variable and store key name that variable
    because you call two time generateKey function in both action handle and terminate…..

Leave a Reply

Your email address will not be published. Required fields are marked *