The newly added 103 status code of HTTP finally comes in handy this time!
Hi, my name is ConardLi.
Speaking of HTTP's 103 status code, you may have heard of it a long time ago, but you may not really understand it.
This is normal, this status code was proposed back in 2017, but there are really few servers and browsers that support it.
Until a few days ago, Chrome announced that it supports HTTP 103 status code in Chrome 103 version, I have to say that foreigners are quite skinny...
Today, let's take a look at what the HTTP 103 status code is used for.
Performance issues with resource loading
Websites become more and more complex over time. The servers of some large websites may need to do a lot of heavy lifting (for example, accessing the database or accessing the origin server's CDN) to generate HTML for the requested page.
However, this server think time can introduce additional delays before the browser starts rendering the page. Because the browser needs to load the HTML page back before it knows which JavaScript, CSS or font files to load next. The middle time is actually wasted. For users to visit our page, this waiting time is a white screen or unavailable state.
Let’s take a look at the resource loading of the Douyin website: the browser has to wait for about 800 ms of the first two HTMLs to load the following JS, CSS and other resource files.
Is there a way to load important static resource files in advance while waiting for the HTML response?
HTTP 103 status code
The HTTP 103 status code (Early Hints) is an informational HTTP status code that can be used to send an initial HTTP response before the final response.
The HTTP 103 status code allows the server to send hints to the browser about some key sub-resources (JavaScript, CSS or font files) or other sources the page might use while the server is processing the main resource.
Browsers can use these hints to warm up the connection and request subresources while waiting for the main resource to respond. In other words, Early Hints can help the browser take advantage of this server think time by doing some work ahead of time, thereby improving the rendering performance of the page.
In some cases, this can help improve LCP (maximum content draw) by at least a few hundred milliseconds. For example, as observed by Shopify and Cloudflare, LCP improved by about 1 second.
Before and after enabling Early Hints
What kind of website is suitable for Early Hints
Before you start using it, you may want to think about what kind of website is more suitable for this optimization.
If your website's main page is very responsive, it may not be necessary. For example, for most SPAs (single page applications), it may not be so useful.
In SPA, most of the logic is on the client side, HTML is very small, and the server that sends HTML is basically a static server without any logic. In most cases, it will only include a Root node and some resource links. Most of the logic and loading time are actually in the packaged JavaScript. In this case, we only need to use conventional rel=preload, rel=preconnect and other means.
But in SSR projects, loading HTML often takes more time on the server side, because the server side may interact with the database and stitch the data into HTML elements. In contrast, loading other script and style resources may take a little less time, which is more appropriate for such sites to enable Early Hints.
Enable Early Hints
In Chrome 103, there is support for HTTP 103 status codes (Early Hints).
The first step in enabling Early Hints is to identify our site's main page, which is the page users typically start when visiting our site. If we have a lot of users from other sites, the home page might be the home page or a popular product listing page.
The usefulness of Early Hints will decrease with the number of times the user navigates our site, because the browser may have requested all required sub-resources in the first few navigations, and a good first impression on the user is the most important thing. !
Having confirmed the site's main page, the next step is to determine which sources or sub-resources would be the best candidates for pre-connect or pre-load. Usually, what we are looking for are the sources and sub-resources that contribute the most to a key user indicator (LCP or FP). Specifically, find sub-resources that block rendering, such as synchronous JavaScript, style sheets, and even web fonts.
Then try to avoid selecting resources that are outdated or no longer used by the main page.
For example, some resources that are frequently updated or have hash (conardli.top/static/home.aaaa1.js), try not to choose, which may cause the resources to be loaded on the page to not match the actual preloaded resources.
For example, let's take an example:
First we go to the server to request the main page:
GET /home.html
Host: conardli.top
User-Agent: [....] Chrome/103.0.0.0 [...]
- 1.
- 2.
- 3.
The server predicts that the site will require home.aaaa1.js and recommends preloading it via Early Hints:
103 Early Hints
Link: </home.aaaa1.js>; rel=preload; as=script
[...]
- 1.
- 2.
- 3.
Then, the client immediately requested home.aaaa1.js from the server. However, by this time the JS resource has been updated, and the main page already needs another version of JS.
200 OK
[...]
<HTML>
<head>
<title>Conardli's Blog</title>
<link rel="script" href="/home.aaaa2.js">
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
Therefore, we'd better choose some relatively stable resources for preloading. We can unpack JS, and split the stable part that changes infrequently and the dynamic script part that frequently updates into multiple resources. We only preload the stable part, and load the dynamic part after the browser gets the main page.
<HTML>
<head>
<title>code秘密花园</title>
<link rel="script" href="/home.js">
<link rel="script" href="/home.aaaa1.js">
- 1.
- 2.
- 3.
- 4.
- 5.
Finally, on the server side, look for the main page request sent by browsers known to support Early Hints and respond with 103 Early Hints. In the 103 response, relevant preconnect and preload hints are included. After the main page is ready, respond as normal. For backwards compatibility, it's best to include the LINK HTTP header in the final response, and even add some obvious key resources needed when generating the main page.
Early Hints response:
GET /main.html
Host: conardli.top
User-Agent: [....] Chrome/103.0.0.0 [...]
103 Early Hints
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
Successful response:
200 OK
Content-Length: 7531
Content-Type: text/html; charset=UTF-8
Content-encoding: br
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style
<HTML>
<head>
<title>code秘密花园</title>
<link rel="stylesheet" href="/main.css">
<link rel="stylesheet" href="/home.aaaa1.css">
<script src="/common.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
What does it have to do with HTTP2/Push?
You may have found it here, this thing is very similar to HTTP2's Server Push.
Server Push That is, when browsing the response HTML file, the server will actively push the required resource file to the browser at the same time.
After the browser receives the pushed resource, it will cache it locally. When parsing the HTML and finding that the corresponding resource needs to be loaded, it will be read directly from the local, and there is no need to wait for network transmission.
Although this sounds amazing, this solution has a very big flaw: Server Push is difficult to avoid pushing sub-resources already owned by the browser. In fact, many resources are already cached when the browser requests it for the first time. This "over-push" can result in less efficient use of network bandwidth, significantly hindering performance benefits. Overall, Chrome data shows that HTTP2/Push actually negatively impacts the performance of the entire network.
So, Chrome announced the removal of support for the HTTP/2 Server Push feature:
In contrast, Early Hints performs better in practice because it combines the ability to send an initial response with hints, where the browser is really only responsible for fetching the resources it actually needs. Although Early Hints has not covered all the use cases that HTTP/2 Server Push can theoretically solve, it solves the problem of wasted network bandwidth and can be said to be an upgraded version of HTTP/2 Server Push.
Support situation
Browser support:
Server support:
- Node.js: Supported through the Fastify plugin;
- Apache: supported via mod_http2;
- H2O: support;
- Nginx: Experimental module.