Written by Ramón Saquete
Índice
We are going to study an advanced WPO technique that, when properly used, will allow us to achieve a considerable improvement in WPO metrics for users who enter our site for the first time and without affecting, or even improving, those of recurring visitors. This is one of the enhancements offered by the relatively new HTTP/2 protocol which is nothing more than the ability to respond to a customer’s request with additional files to the one requested. This is why this technique is known as “HTTP/2 Server Push“.
How should HTTP/2 Server Push be applied?
Usually, when we request a page from the browser, the server returns the HTML and the browser analyzes it with an algorithm called preload scanner, with which it looks for the resources it has to request from the server before starting to assemble the page. What HTTP/2 Server Push does is to allow us to advance the loading of the resources so that they are downloaded at the same time as the HTML, thus avoiding the browser having to ask for them after downloading and parsing the HTML.
In order to use this feature, both the client and the server must be ready to use it. Currently, all browsers already allow it, but not all web services with HTTP/2 support the use of HTTP/2 Server Push, so we usually need to have the most updated versions of the web service and their respective modules or extensions for HTTP/2. Not many hosting or even CDN services currently allow its use.
To apply the technique correctly, we must advance the critical resources for new visitors: first of all, remember that the critical resources are those necessary to visualize the part of the page that the user views first. For example, in a web site where the HTML is generated on the client with JavaScript, this will be a critical resource, but otherwise it may not be. In general, critical resources will always be parts of the CSS, some fonts and, exceptionally, some images, i.e. everything that is used to paint the important parts of the top of the page (the “above the fold”) and make it interactive. However, it is not advisable to load all the critical resources in advance, since we could slow down the download of HTML, which is the most important of the critical resources. So I recommend, in general, not to advance images and always test, with a WPO tool such as Lighthouse or webpagetest.org, if the way this technique is applied is optimizing or de-optimizing the loading, painting and interactivity of the page.
Applying this technique on the critical CSS, has the advantage that it is no longer necessary to embed it in the HTML, so it can be cached in the browser, so it does not increase the size of the HTML for recurring visits, so these will also have a small improvement. Likewise, if an image is advanced, it is not necessary to embed it in the HTML and it can be cached.
HTTP/2 Server Push implementation
In the implementation, besides pushing some resources, we also have the option of preloading them, we will study the difference below and how each case is implemented.
No preload and no Push
Let us first look at an unoptimized case. Suppose we have an HTML page that links to a CSS and an image, then within the CSS it links to a font. The HTTP/2 download would normally occur as follows:
The image and the style sheet are downloaded at the same time because they are both referenced from the HTML and HTTP/2 allows multiple files to be sent at the same time multiplexed.
Push
Now we want to optimize the previous case and we assume that the full CSS and the font are a critical resource, so we want to advance the download of these resources to happen as follows:
To implement it we only need to include the resources we want to “push”, in the header of the requested file with the Link parameter as follows:
Link: </estilo.css>;rel=preload;as=style,
</fuente.woff>;rel=preload;as=font
In the attribute “as” we can have these values or we can omit it if it is an HTML document.
Preload
If we include the word nopush, instead of the resource being sent at the same time, it will be requested when the browser parses the request header during the HTML download. We will call this, which is not a push, a preload.
Link: </app/style.css>; rel=preload; as=style; nopush
This behavior is similar to what we would have if we use the same directive, in the HTML of the page, as follows:
<link rel="preload" as="style" href="/app/style.css" />
By doing the latter, the browser downloads the HTML and when it finds this tag in the header, it requests the resource from the server. This doesn’t make much sense if we are going to ask for a style sheet that will also be found in the HTML header, but it can make sense for advance loading of a font that is linked from CSS or any resource that is in the third level of the resource dependency tree and we do not have HTTP/2 Server Push, since we avoid the browser having to download and parse the CSS to request it. Graphically:
Resources pushed into the network cascade
When a push is implemented, you must check in the browser’s network cascade if the resources you want are being pushed. If we have mistyped the header, they will not appear pushed so the download initiator will be “Parser” which is the preload scanner parser, and if the server does not allow HTTP/2 server push, it will appear that the initiator of the download has been “OtherThe request will be triggered when the HTTP header is seen, but it will not be sent simultaneously with the HTML, but will behave almost like a “HTTP request”. preload made from the HTML header.
Let’s see some examples of each case in the Google Chrome download cascade, which is the only one that displays Push correctly:
In this first screenshot we see an image whose initiator is “Other” and that is not downloaded until it starts parsing the CSS, let’s see what happens if we preload it with rel=”preload” in the HTML header:
The initiator is now the HTML parser, as it is now loaded when you start parsing HTML.
Let’s see what happens with a Push:
In this case a CSS has been pushed, so when the HTML has finished downloading, it has already been downloaded.
Beware of the cache
It should be taken into account in the implementation of pushes that this optimization should apply only to new userssince appellants will have these data in the cacheIt is therefore not necessary to send them this data again, since if they have been set up correctly, it is not necessary to send them again, since they have been set up correctly. the HTTP protocol cache headersThese will be sent with the “pushed” files.
If a cached file is pushed, sending the file will be cancelled when the browser discovers that it already has that resource in cache, but resources are still wasted.
As in the request, we cannot know a priori if the user is new or recurrent, the best strategy we can apply is to set a cookie on the first visit, where we indicate in the value of the cookie, the version of the resources that have been sent. That way, when we receive a new request from that client, we will know whether or not we have to send those resources by Push. Although not having the cookie does not guarantee that the resources are not cached in the client, but we avoid most of the unnecessary sending.
In the future it is expected that the specification will be extended to address this problem, but for now it must be solved by the developer.
Specific implementation for the web service
Adding headers to HTML is not the only way to implement pushes. We can also make use of specific directives of the web service we are using, so that we can push the resources even before we have to start processing the HTML on the server. For example, in Apache we would do it with the directive H2PushResource from a .htaccess and with which we could also indicate the priority of some pushes over others, otherwise it will decide the priority by file type. In the following example the download of the CSS is prioritized over the JavaScript using this directive:
H2Push on
<Location /index.html>
H2PushResource "/css/estilos-criticos.css" critical
H2PushResource "/js/javascript-critico.js"
</Location>
Alternative ways of suggesting how to load resources and other considerations
Apart from being able to use the “rel=preload” attribute, either in the HTML link tag or in the HTTP Link header, we can also use the rel=prefetch, rel=prerender, rel=preconnect, rel=dns-prefetch and rel=”preconnect” values to suggest to the browser how to load the resources with the following meanings:
- prefetch: it is used to download resources that are going to be seen after the current page, so they are downloaded after the download of the rest of the resources is finished. Safari does not allow it.
- prerender: like the previous one, it is used to download resources to be viewed after the current page. after the download of the rest of the resources has been completed but, in addition, the browser can to initiate the painting of these resources when you have already painted the current page and have free CPU and memory resources. At the moment few browsers support it, so it is recommended to use the previous one.
- dns-prefetch: it is used to advance the DNS resolution of external domains that load resources on our page. All browsers allow you to use it.
- preconnect: serves to preempt DNS resolution, TCP connection establishment and TLS negotiation (if using HTTPS). This saves more round-trip cycles than dns-prefetch, but there are a few browsers that do not support it.
Additionally, we can add media queries to load certain resources depending on the screen size. You can also consult here how to optimize the fonts used in a Web site.
We can also apply the link tag values used for SEO, such as rel=”canonical” or rel=”alternate”, although this case has nothing to do with suggesting the way in which resources are loaded:
- canonical: used to indicate the canonical URL to the spider to prevent variants of the same URL from being indexed as duplicate content. Sending this parameter in the header, rather than in the body of the HTML, is the only way to set the canonical URL for non-HTML files and is currently used only for PDFs. Example:
Link: <http://www.-----.com/articulo.pdf>; rel="canonical"
- alternate: serves to indicate an alternative version of the current URL to the spider, it can be a different language or language and country or a specific version for mobiles. Example:
Link: <http://www.-----.com/articulo>; rel="alternate"; hreflang="es-ES" Link: <http://www.-----.com/article>; rel="alternate"; hreflang="en-GB"
- amphtml: used to indicate the alternative AMP version of a non-AMP page. Example:
Link: <http://www.-----.com/articulo>; rel="amphtml";
Finally, we can chain several Link headers by separating them by commas in the HTTP header:
Link: <//pagead2.googlesyndication.com>; rel=dns-prefetch,
</js/bootstrap.min.js>; as=script; rel=preload,
</ads.html>; rel=prerender,
</css/bootstrap.min.css>; as=style; rel=preload
This saves some code over entering a Link tag in the HTML or a new Link parameter in the header for each resource.
Conclusions
The HTTP/2 Server Push technique is not easy to implement. and if it is misapplied, by advancing too many resources or non-critical resources and disregarding the cache, we could worsen performance both new and returning users, but if we do it correctly, will significantly improve WPO metrics, especially from new users, so we will improve the first impression that the site generates in these users.
Since this technology still has some aspects in the experimental phase, implementation is likely to change in the future and become easier and simpler.It currently does not make much sense that to do a push in the HTTP header you have to use a code equivalent to a preload in the HTML header and to do a preload in the HTTP header you have to add nopush. It should also include improvements, it would be very interesting if it could be used to speed up redirects, making the web service send a push of the HTML to be redirected to automatically, which is something that currently does not even work manually.
Update: On September 27, 2022, HTTP/2 Server Push support is removed from Chrome, due to the difficulty of its implementation, discussed in this article, and its low adoption.
Bibliography
https://httpd.apache.org/docs/2.4/mod/mod_http2.html
https://www.w3.org/TR/preload/#server-push-http-2
https://www.w3.org/TR/resource-hints/