Gzip Compression with Laravel Vapor
James Bannister • July 30, 2021 • 2 minute read
laravelI was answering some Laravel questions on StackOverflow this week when I stumbled on a question asking how to enable GZIP compression on responses when using Laravel Vapor. We host a number of applications on Laravel Vapor and this was something we'd solved, but a cursory search of Google didn't return anything that explained how to do this (at least at the time this was written).
To solve this, we added some middleware that GZIP'd the response when the requesting client accepted gzip encoding. The same approach could be used to add other types of encoding like Brotli, compress, deflate etc:
1<?php 2 3namespace App\Http\Middleware; 4 5use Closure; 6use Illuminate\Http\Request; 7 8class GzipEncodeResponse 9{10 public function handle(Request $request, Closure $next)11 {12 $response = $next($request);13 14 if (in_array('gzip', $request->getEncodings()) && function_exists('gzencode')) {15 $response->setContent(gzencode($response->getContent(), 9));16 $response->headers->add([17 'Content-Encoding' => 'gzip',18 'X-Vapor-Base64-Encode' => 'True',19 ]);20 }21 return $response;22 }23}
Our middleware first processes the request.
Then we check whether gzip
is one of the supported encoding types in the request. Supported encodings are sent as an
Accept-Encoding
header in the request.
We also check that the gzencode
function exists to prevent any issues from trying to use it.
Assuming we want to encode the response and are able to, we set the content of the response to be the compressed version.
In the snippet above, we use the "level" of compression to 9
which is the maximum level of compression. You can choose
to not include this argument and it will fallback to use the default or you can specify a different level of compression if that
makes more sense to you.
Finally, we update the headers of the request to add the Content-Encoding
header to indicate that the response is GZIP'd
and then we have to set the X-Vapor-Base64-Encode
header as we are sending a binary response. You can read up more on
the Vapor Header in the docs on Binary Responses.
Like any middleware, you can choose to apply this at a per route level, add it to a particular group of middleware, or add it as global middleware. In our apps, we've added it as global middleware and then we just ask for a GZIP'd response when we need to do so.
I hope you found this useful. If you have any feedback, thoughts, or different approaches to this then I'd love to hear from you; I'm @jryd_13 on Twitter.
Thanks!