Laravel: Reusing a HTTP/2 connection

No need to let the connection go from your server

Italo Baeza Cabrera
4 min readOct 12, 2022
Photo by SpaceX on Unsplash

Most of you who use the HTTP Client included in Laravel tend to be wary of doing multiple requests to a server. The most common problem is paying the connection overhead over and over again, so normally you will want to make request only when necessary and cache the response when needed.

By today standards, HTTP/2 has become a very common protocol among modern web servers — HTTP/3 just became RFC — and one of the key features is connection reuse. Clients are encouraged to keep the connection open for additional requests, which is very useful for Internet browsers when there are plethora of resources that must be fetched.

What if I told you that you can use HTTP/2 in Laravel with the included HTTP Client, and even reuse the same connection?

The secret recipe

To make use of HTTP/2 on the Laravel HTTP Client we need two things: the cURL extension enabled, and to explicitly use HTTP/2. To reuse the connection we need to simply reuse same Guzzle client instance.

Sounds a bit tedious but the setup is relatively easy.

1) Let’s use cURL for this

The first part is triple check on php.ini. Check that the line with extension=curl is uncommented and the extension is loaded through php -m. You may be amazed how some people think they have it enabled when it’s not.

Without cURL, Guzzle will fallback to native sockets and HTTP/1.1, which is slowest than cURL in most scenarios.

A set of PHP extension in the INI file.

2) Let’s use HTTP/2

The next step is to tell Guzzle that it should connect through HTTP/2. By using the withOptions() method, we can put a nice 2.0 on the version key.

3) Let’s reuse the connection

Finally, the magic step is reusing the same Guzzle Client. Doing two requests to the same server will not reuse the same connection, because, the client will be created anew for each request. Instead, we first build a client, save it somewhere, and inject it into the requests to be sent.

Once done, we can simply reuse the same client by setting it into the pending request through setClient().

If we fire these two requests, the responses will come just fine. If you’re curious, we can add the debug key with true to check what Guzzle is doing in each request.

If we see a line saying “Re-using existing connection!” for the same host, Congratulations! You’re using HTTP/2 the way was meant to!

Some servers don’t play nice

There are three things to consider for HTTP/2 requests to work.

The first, and most obvious, is that the server must support HTTP/2. Some servers will tell or document it somewhere, others won’t guarantee that. For example, Stripe API does support HTTP/2 but doesn’t say it so officially. Always double check with a quick test if it does before using it, or ask on their forums/repositories.

For live Internet-facing servers, HTTP/2 support is usually not a problem because HTTPS is standard, but some local development servers may come with some problems because they’re not encrypted, and serving local TLS is a pain in the ass.

Let’s take an example for SurrealDB and my Subscriptions for Laravel library.

After a brief conversation, SurrealDB confirmed it supports HTTP/2 over HTTP, which is thanks to the underlying warp/hyper library. The problem is that warp doesn’t allows protocol upgrade if it’s not encrypted. Every time I executed a query to retrieve all the subscribers for a particular plan, a new connection spawned using HTTP/1.1.

In the cases when we are 100% sure the server supports HTTP/2, we can forcefully connect that way. To do that, we can signal cURL to not ask for upgrade, but use HTTP/2 immediately, by setting CURLOPT_HTTP_VERSION to CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE.

If we debug the connection as we did before, we will see that Guzzle immediately uses HTTP/2 instead of asking for an upgrade, and further connections will be reused. 🥳

With that, your requests should be blazing fast, and you shouldn’t be afraid to make multiple requests to one server as long you can reuse the same connection.

--

--

Italo Baeza Cabrera

Graphic Designer graduate. Full Stack Web Developer. Retired Tech & Gaming Editor. https://italobc.com