Accelerate redirects with HTTP/2 server push

You can achieve low-latency responses to redirects with HTTP/2 by pushing the resource at the redirected location along with the response that informs the web browser about the redirect. It’s even easy to set up.

Traditional HTTP redirects have required clients to first wait for the server to tell them about the redirect, and then issue a new request to the redirected location. This extra round-trip back and forth between the browser and server introduce higher latency times before the final resource is delivered to the client.

A HTTP/2 compatible server can be configured to handle redirects in a much more efficient way and remove the latency penalty. When a HTTP/2 server handles a redirect, it can not only inform the client about the redirect — but also preemptively push the new location to the client even before it knows it has to request it.

At , few HTTP/2 capable clients and servers have implemented cross-origin push handling yet. However, as long as you’re redirecting within the same protocol and domain, you can benefit from pushing any redirects within the same origin. HTTP/2 push delivery is supported by recent versions of all major web browsers including Firefox, Google Chrome, Microsoft Edge, and Safari.

Server initiated push can be implemented in many different ways. The method that has caught on with web developers and server implementors alike involve introducing a simple HTTP Link response header. This can easily be added in on existing server and backend solutions, with the server handling the details. Since this method is easy to explain, I’ll show you how it can used to automatically adding server push support to your existing redirects.

Below, you’ll see a simple Link response header that would instruct a HTTP/2 capable server to push https://www.example.com/new-location to the client:

Link: <https://www.example.com/new-location>; rel=preload

By including this response header, you can push any number of supplemental resources to the client. Common examples of other types of resources that could be pushed with this method include critical stylesheets and scripts required for a page to render quickly. Any resource can be pushed to the client, but websites should take care to not over-do it by pushing overly large resources. Developers should also avoid pushing the same resources multiple times to the client and rather leverage client-side caching.

You can easy add this header to any redirects by copying the contents of the Location response header. The Location header is required for redirects and must contain an absolute URL pointing to the redirected location.

The following is a Varnish Cache configuration example, that doubles as pseudo-code to show you how you can turn a plain old redirect to a redirect that also pushes the final destination location:

sub vcl_deliver {
  if ((resp.status == 301 || resp.status == 307 ||
       resp.status == 302 || resp.status == 308)  {
    if (resp.http.Location ~ "^https://www\.example\.com/") {
      set resp.http.Link = "<" + resp.http.Location + ">; rel=preload; as=document"
} } }

Depending on your choice of web server and infrastructure, adding the Link response header may be enough to enable HTTP/2 server push. For Apache, IIS, and Nginx, the above should be enough assuming the additional header is introduced at the right time in the processing chain. HTTP/2 server push can be implemented in a number of ways, and you risk not introducing preload Link header early enough in the processing chain. You should make sure to test and verify that your setup works.

You can also introduce this header in your application backend when creating an redirect. You’ll likely have the best information about the redirect at the time the redirect is created, so that’s a good time to include the preload Link header.

Here is an example using mod_rewrite to have the Apache HTTP Server produce the header when redirecting from /old/ to /new/:

RewriteCond %{REQUEST_URI} "^/old/(.*)"
RewriteRule "^/old/(.*)" /new/$1 [redirect=301,env=h2pushredir:/new/$1]
Header always append "Link" "<%{h2pushredir}e>; rel=preload; as=document" env=h2pushredir

Lastly, I’d also like to stress the importance of testing that your implementation detects and cancels redirect loops. If you implement automatic redirect pushing using a method similar to the one I outlined above, It would be most unfortunate to get your server stuck pushing an infinite number of redirects to a client in an newer ending loop.


Update (): This didn’t turn out quite the way I’d envisioned. Chrome has announced plans to remove support for server push.

Within a few years, I expect that we’ll see most HTTP/2 web servers automatically push the new location along with any redirects they serve. (At least within the same origin.) It greatly improves performance of redirects, reduces latency, and it’s so easy to implement!

Web servers will need to identify and put in place protections against redirect loops, but other than that: there shouldn’t be any roadblocks to enabling redirect-pushes by default.

At the very least, web servers will implement redirect-pushes by default for any redirects that have been created through server configuration. They may choose to not interfere with any redirects issues by a higher level applications, but I don’t see any major reasons why they wouldn’t want to handle those as well.

Until web servers start taking care of this on their own, web developers need only spend a few minutes of their time to speed up all redirects. —and we all want faster redirects, right?