Understanding the 304 Not Modified Response in HTTP Caching

When developing web applications, efficient resource handling is crucial for performance, especially when it comes to file access and browser caching. One way to optimize this process is by correctly utilizing the 304 Not Modified HTTP response. This response informs the browser that the resource it requested has not changed since it was last retrieved, allowing the browser to continue using its cached version rather than downloading it again. But how do you know when to send this response? Let’s break it down step by step.

Key HTTP Headers to Check

To determine whether to send a 304 Not Modified response, you need to check specific HTTP headers sent by the client’s browser. The two main headers to focus on are:

  1. Etag: This header serves as a unique identifier for a resource at a specific version. The browser compares its cached Etag with the server’s Etag to see if they match.
  2. If-None-Match: This header is sent by the browser and contains the cached Etag value. If the resource has not changed, the server can respond with 304.

What to Look For

  • If the Etag from the browser exists: If the browser includes either the Etag or If-None-Match headers in the request, it indicates that it has a previously cached version of the resource.
  • Quoting Considerations: Browsers sometimes quote the Etag value. Make sure to strip these quotes before comparison.

Necessary Headers for the Initial Response

When initially sending the resource (typically with a 200 OK response), it’s essential to include relevant headers that inform the browser about the resource state:

  • Last-Modified: Indicates the last time the resource was changed. This can be an alternative check for cache validation alongside Etag.
  • Etag (as mentioned before): This should be generated for the resource and included in the response headers to facilitate future cache validation.

Implementing the Logic

Here’s a simplified pseudocode example that demonstrates how to implement the logic for sending a 304 Not Modified response:

server_etag = gen_etag_for_this_file(myfile)
etag_from_browser = get_header("Etag")

if etag_from_browser does not exist:
    etag_from_browser = get_header("If-None-Match")
if the browser has quoted the etag:
    strip the quotes (e.g. "foo" --> foo)

set server_etag into http header

if etag_from_browser matches server_etag
    send 304 return code to browser

Example Server Logic Snippet

Here’s how you might implement this in your server logic:

/* the client should set either Etag or If-None-Match */
mketag(etag, &sb);

etagin = apr_table_get(r->headers_in, "Etag");
if (etagin == NULL)
    etagin = apr_table_get(r->headers_in, "If-None-Match");
if (etag != NULL && etag[0] == '"') {
    /* Strip quotes if present */
    int sl; 
    sl = strlen(etag);
    memmove(etag, etag+1, sl+1);
    etag[sl-2] = 0;
}   

apr_table_add(r->headers_out, "ETag", etag);

if (etagin != NULL && strcmp(etagin, etag) == 0) {
    /* If the etag matches, return a 304 status */
    rc = HTTP_NOT_MODIFIED;
}

Final Thoughts

By knowing how and when to send a 304 Not Modified response, you can effectively reduce server load and improve user experience. Don’t forget about the importance of including the Etag and Last-Modified headers during the initial response to allow the client to make accurate cache validation requests later on. If you have questions about Etag generation or need further implementation help, feel free to reach out for more detailed examples. Happy coding!