Enhancing Application Performance with Client-Side Caching: Cache-Control and ETags.

Enhancing Application Performance with Client-Side Caching: Cache-Control and ETags.

Introduction

Currently, I’m working on a project where I’m using cache control headers and ETags to take full advantage of client-side caching. It’s been such an interesting experience that I’m sharing the concept in this article

Need of caching

We all understand what caching is and why it's so important, but let me quickly give you an overview because I’m diving deep into the caching approach and why it’s a game-changer in performance.

Every time we visit a website, our browser requests data from the server. Without caching, it fetches everything fresh every single time, even if nothing has changed. This slows down our load times. Caching solves this by storing frequently used data (like images, scripts, styles, or JSON data) in cache memory. So we can reuse it instantly without repeating the heavy tasks.

Where do we cache our data?

We can cache our data in different places:

  1. Browser Cache: Our browser stores data like images, CSS, and JavaScript locally so that the next time we visit the site, it can load faster.
  2. CDN (Content Delivery Network): CDNs cache data on servers around the world, reducing the distance and time it takes to deliver content to users.
  3. Server-Side Cache: This involves storing pre-processed data on the server to serve faster responses to clients.

Client-Side Caching

Suppose we have data that doesn’t change often but is accessed frequently. For this type of data, we can cache it in the browser. By doing so, the user's requests won’t go to the server every time. Instead, the data will be served directly from the browser cache, improving load times and reducing server load.

Client-side caching is crucial for improving website speed and performance. It allows data to be stored closer to the user, reducing the need for repetitive requests to the server. This results in faster load times, reduced server load, and a better overall user experience.


Fig-1: Overview of Client-Side Caching

This is where the Cache-Control header becomes essential. It’s a simple and powerful tool that lets us control how and for how long data should be cached.

Cache-Control Header

The Cache-Control is an HTTP header that can be included in both requests and responses. It serves as a set of instructions for the browser, telling it how to handle caching for a specific resource.

When the browser receives a resource with this header, it uses the values specified in it to determine whether and how to cache the resource. This caching can occur at various levels, such as the browser, CDN, etc.

Here's how to set it up in (node.js / Nest.js):

res.set('Cache-Control', 'public, max-age=3600'); // Cache for 1 hour        

All we need to do is follow the steps above—it's that simple! Easy, right? ??

Key Directives in Cache-Control

  • public: Allows the response to be cached by any cache (browser, CDN, proxy).
  • private: Restricts caching to only the browser; CDNs and proxies won’t cache it.
  • max-age=[seconds]: Specifies how long (in seconds) the resource should be cached.
  • no-store: Prevents caching entirely.
  • no-cache: Forces the browser to validate the cache with the server before using it.

The Cache-Control header is a highly effective way to cache static data, such as HTML, CSS, image files, and even formatted data when needed.

Cache-Control Sets the Rules, ETag Checks the Freshness!

While the Cache-Control header is great for specifying how long resources should be cached, sometimes we need a way to check if the cached resource is still valid. For example, what if the resource changes on the server before the cache expires? This is where ETag and the 304 Not Modified status come into play.

I mean, Cache-Control sets the rules, But ETag brings the gossip: Is Your Cache Still Fresh? ??

ETag (Entity Tag)

An ETag (Entity Tag) is like a unique fingerprint for a file or resource on a server. It helps the browser check if the file has changed since it was last cached.

Here’s how it works:

1. The server Assigns an ETag:

When a client requests a resource, the server generates a hash value using the resource. Then use it as a ETag header in its response (I mean header name is Etag and the value is generated hash value). For example:

HTTP/1.1 200 OK
Content-Type: application/json
ETag: "abc123"        

2. The Client Stores the ETag:

The client stores the ETag value along with the resource in its cache.

3. The Client Sends a Conditional Request:

When the client requests the same resource again, it includes the If-None-Match header with the previously stored ETag:

GET /resource HTTP/1.1
If-None-Match: "abc123"        

4. The server validates the ETag :

a. The server retrieves and processes the data, and then generates a new hash based on the fetched content.

b. If the ETag doesn't match (indicating the resource has been modified), the server sends the updated resource along with a new ETag.

c. If the newly generated hash matches the provided If-None-Match header value, it means the content hasn't changed yet. In this case, the server responds with a 304 Not Modified status and omits the resource body, signaling the client to use its cached version.

HTTP/1.1 304 Not Modified        


Fig-2: How ETag is generated and passed with response


How the hash can be generated?

The server generates a hash using the data of the resource it serves. Typically, this is done by converting the resource into a consistent format (e.g., JSON) and then applying a hashing algorithm like MD5, SHA-1, or SHA-256.

Let’s say it is our data:

[
   { "id": 1, "name": "A" },
   { "id": 2, "name": "B" }
]        

To generate the hash for this data, First, we need to serialize it (format it into a string)

// After converting into a string
'[{"id":1,"name":"A"},{"id":2,"name":"B"}]'        

Then hash the string using a hashing (Let’s say SHA-256) algorithm:

Hash: a84d97d60d294472b8d3f6b74bc3327c1ebcd05f        

We can return the hash as the ETag.

Advantages of This Approach

  1. Stateless: The server doesn’t maintain any ETag history or additional storage.
  2. Dynamic: As long as the resource data is available, ETags can always be recalculated.
  3. Accurate: Any change to the resource data automatically results in a different ETag.

Limitations

  1. Server Overhead: Generating ETags for large or frequently changing resources can be computationally expensive.
  2. Distributed Systems: Maintaining consistent ETags across multiple servers (e.g., in a load-balanced setup) can be challenging.

Best Practices to Overcome Limitations and Achieve Optimal Results

Combining ETags with other HTTP headers like Cache-Control and Expires can help improve caching and get the optimal benefits considering the limitations:

Example Response Headers

HTTP/1.1 200 OK
Content-Type: application/json
ETag: "1234567890abcdef"
Cache-Control: public, max-age=3600, must-revalidate
Expires: Mon, 20 Jan 2025 10:00:00 GMT
        

How It Works

  1. Cache-Control: This tells the browser and caches how long they can store the resource and whether they should re-validate the resource after it becomes stale. In this case, it's valid for 1 hour (max-age=3600), and the cache must re-validate it after that time.
  2. ETag: The ETag header allows the server to track changes in the resource. If the resource hasn't changed, the server will respond with a 304 Not Modified status.
  3. Expires: Provides an explicit expiration time for the resource, telling the cache when to consider it stale.

Fig-3: Overview of using cache-control and ETag header combination

In short, Feed the data from the cache for an hour, then send it on a 'Is this still fresh?' mission to the server because even the cache needs a reality check!

Conclusion

To sum up, I explored the power of Cache-Control headers and ETags to optimize client-side caching for my project. I aim to share what I’ve learned, create a resource for others, and welcome any feedback on topics I might have missed. Thank you for reading, I truly appreciate your time! ??

要查看或添加评论,请登录

Md. Mizanur Rahman的更多文章

社区洞察

其他会员也浏览了