Headers for large files
HTTP headers Content-Length, Content-Encoding, and Transfer-Encoding impact the transmission of large files in web applications. With a practical Node.js server example, learn about header combinations and the importance of the Content-Length header and gzip compression for optimizing web performance.
When you have a lot of information to show on the screen, there are two common choices:
- pagination
- streaming
But you know what? You can also just send the whole thing to the user. Let's explore this straightforward approach together.
Headers
We'll explore three crucial headers - Content-Length
, Content-Encoding
, and Transfer-Encoding
- and see how different combinations of these headers can influence the rendering on the browser.
Content-Length
It specifies the size of the payload in bytes. It helps the recipient (in our case, the browser) know how much data to expect. It's like a heads-up, ensuring everyone is on the same page about the amount of content coming their way.
Content-Encoding
It tells the browser how the content is encoded or compressed. It's like a secret code that both the server and the browser understand. Common encodings include gzip and deflate. When the browser sees this header, it knows how to decode the content for a smooth display.
Transfer-Encoding
This less-known header handles the encoding of the message itself during transmission. It can be sent all at once (like a single big parcel) or in smaller pieces (like breaking it into multiple smaller packages).
Server
To see how the browser reacts to different combinations of these headers, let's set up a basic Node.js HTTP server.
The server is designed to handle incoming requests for any path, offering flexibility through optional query parameters:
content-length
: If set totrue
, this parameter adds theContent-Length
header to the response.transfer
: This parameter sets theTransfer-Encoding
header, with options for:identity
: Instruct the server to send the document as a whole.chunked
: Directs the server to send the document in chunks.
gzip
: If set totrue
, the server retrieves the zipped version of the file. In this case, theContent-Length
(if set) reflects the size of the zipped version.
The content within the HTML files is not the focus; their substantial size is (AKA they're LARGE).
These files are maintained in two versions: plain and gzipped. While it's generally not a recommended practice for real servers to adopt dual storage, here the intent is to avoid introducing additional overhead in the case of zipping.
Testing
I'll now test the server using Firefox, monitoring how response times vary with changes in the headers. If you're following along on your machine, make sure to disable the cache and consider checking the 'Preserve logs' checkbox for a more accurate observation.
Initially, we make a request without query parameters, letting the Node.js HTTP server handle it by default. The default Transfer-Encoding
observed is chunked
, aligning with the behavior of passing ?transfer=chunked
. Node.js aims to be non-blocking, and this choice ensures smoother processing.
Now, let's spice things up by passing the query parameter ?transfer=identity
. This time, the request takes notably longer to complete.
To remedy this, we introduce the Content-Length
header with ?content-length=true&identity=true
, resulting in a significant reduction in duration. It's like mailing a package in one piece. Including the Content-Length
header is the friendly note that says, 'Hey, your package is this big!'. Without it, the client might fumble guessing the size, leading to some awkward data processing moments.
🔑 message In 'identity' mode, be a good server and always attach that
Content-Length
header.
As a final observation, we note that the presence of the Content-Length
has no impact when the transfer method is set to chunked.
🔑 message Not only there's no need for the
Content-Length
header`, but using both is actually contradictory. In 'chunked' encoding, the size of each chunk is self-contained, and a final zero-size chunk does the job of marking the end of the response.
Compression
When using the gzip-compressed resource, the behavior aligns with what we've just explored. In the identity
transfer mode, it remains crucial to provide information about the content length, regardless of the content encoding.
Now, let's talk about compression benefits and a trade-off. Opting for gzip compression offers two wins:
- it conserves disk storage on your server.
- it trims down on bandwidth usage.
However, there's a catch - the browser has to roll up its sleeves and put in a bit more effort to decompress.
If you are interested in Web Performance you definitely need to know about Web Caching (posts series) .
On This Page