Laravel: The hidden SetCacheHeaders Middleware

Now that we know how the HTTP Cache Control works, we can understand what this middleware tries to achieve.

Or skip the next section for the useful part.

How the SetCacheHeaders middleware works?Let’s check the source code.

As you can see, there are five main statements inside the handle() method in this middleware.

Trying to verbalize what each does:It starts with checking if the request is GET or HEAD.

You can’t cache a POST response, since this method means changed things.

Check if you passed any parameter to the middleware, and parses them into the Response headers using the handy parseOptions() method.

If the etag option has been set, it will automatically hash the response content so it can be quickly compared against the etag the Request sent.

It will set the Cache-Control options inside the Response headers.

And finally, it will check if the response has not been modified.

If it wasn’t, it will remove the content and only return the etag, saving precious kilobytes.

The focus is on the third and fifth points.

The browser will make a Request to the application with the etag of the cached response, if the original response came with that.

Your application will receive the etag, process the whole request, and in the end, hash the content again in the etag of the response.

By comparing both etag the application can know if it should send the whole response again, or only the same etag which tells the browser the content hasn’t been changed.

Artistic representation of how the etag works in this application.

That emphasis on “process the whole request” is the key part.

The application or the browser won’t know if the content has changed unless the whole response is ready, meaning: all of your application logic will run from start to finish anyways.

If you need a more aggressive caching, you could set your eyes on the awesome Spatie’s Response Cache.

Personally, I consider the Cache Control as a niche header.

If I would want to implement this technique, it’s better to cache the response in-server and then add the etag to save time on both ends.

Using the SetCacheHeaders middlewareNow that we know what this middleware does, it’s easy to just use it.

Let’s use a simple real-world example, like my eternal Podcast application.

I’m my Podcast application, the Home page has a large list of latest published podcasts, which varies depending on the user authenticated and subscribed podcasts.

My metrics says that there is, at least, 5 minutes between each podcast publication.

Let’s see Google’s flow chart about what cache-control policy to use:Google Developers — Google (2019)Okay, we get the idea:no-cache and etag will allow the user to refresh the page (even before the expiration time) without downloading the whole page if the latest published podcasts are still the same.

private says the homepage is per-user, and should be cached only in the user device rather than, for example, a proxy.

max-age=360 will set an expiration time of 5 minutes, since after that time surely there is a new Podcast published.

Route::get('/', 'PodcastController@index') ->middleware('cache.

headers:no-cache,private,max-age=360;etag');And that’s all.

There is no need to create your own middleware or hack into Apache or NGINX, this comes out-of-the-box ready to be used.


. More details

Leave a Reply