Gzip Compression with Laravel Vapor

James Bannister • July 30, 2021 • 2 minute read

laravel

I 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:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

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

        if (in_array('gzip', $request->getEncodings()) && function_exists('gzencode')) {
            $response->setContent(gzencode($response->getContent(), 9));
            $response->headers->add([
                'Content-Encoding' => 'gzip',
                'X-Vapor-Base64-Encode' => 'True',
            ]);
        }
        return $response;
    }
}

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!