Nginx – Update Cache-Control max-age when srcache returns response from cache

cachehttp-headersnginx

I have configured Nginx to use srcache (along with the redis and redis2 modules). Server-side caching works great. My application responds with the appropriate Expires and Cache-Control headers, and srcache will store and fetch from the Redis cache accordingly.

I would like my response to be cacheable by browsers and proxies outside of my servers. The Expires and Cache-Control headers are sent. However, the Cache-Control max-age isn't automatically updated. I assume this is because this header is actually stored in the cache. Note the dates on these responses, and that max-age in the Cache-Control header is still at 2592000… its initial value.

HTTP/1.1 200 OK
Server: nginx/1.2.9
Date: Tue, 01 Jul 2014 15:18:19 GMT
Content-Type: application/javascript
Content-Length: 2710
Connection: keep-alive
Vary: Accept-Encoding
Expires: Thu, 31 Jul 2014 15:13:00 GMT
Cache-Control: public, max-age=2592000, must-revalidate, proxy-revalidate
X-SRCache-Key: fde32bfe93fcf90c398e9ed585991146
X-SRCache-Fetch-Status: HIT
X-SRCache-Store-Status: BYPASS


HTTP/1.1 200 OK
Server: nginx/1.2.9
Date: Tue, 01 Jul 2014 15:22:13 GMT
Content-Type: application/javascript
Content-Length: 2710
Connection: keep-alive
Vary: Accept-Encoding
Expires: Thu, 31 Jul 2014 15:13:00 GMT
Cache-Control: public, max-age=2592000, must-revalidate, proxy-revalidate
X-SRCache-Key: fde32bfe93fcf90c398e9ed585991146
X-SRCache-Fetch-Status: HIT
X-SRCache-Store-Status: BYPASS

Is there any way to correct this problem? Here is the relevant section of my Nginx configuration:

location / {
    # Caching keys
    set_md5 $srcache_key $request_uri; 

    srcache_ignore_content_encoding on;
    srcache_methods GET;
    srcache_fetch GET /redisFetch $srcache_key;
    srcache_store PUT /redisStore key=$srcache_key&exptime=$srcache_expire;

    add_header X-SRCache-Key $srcache_key;
    add_header X-SRCache-Fetch-Status $srcache_fetch_status;
    add_header X-SRCache-Store-Status $srcache_store_status;
    add_header X-SRCache-Expire $srcache_expire;

    include /apps/*/nginx/api.conf;
}

location = /redisFetch {
    internal;

    set $redis_key $args;
    redis_pass redis_cache;
}

location = /redisStore {
    internal;

    redis2_query set $arg_key $echo_request_body;
    redis2_query expire $arg_key $arg_exptime;
    redis2_pass redis_cache;
}

Best Answer

The max-age value specifies a number of seconds for which the object should be regared as fresh. Ie it will be cache-able, including by browsers for this many seconds, so you may not really need to do anything to Cache-Control: max-age if enabling that caching is your goal. More of a worry is your Pragma: no-cache header. Also in your Cache-Control header, you specify must-revalidate. That means that clients will typically still need to make a request, but the request will include an If-Modified-Since header, and the server can then just send a 304 Response, and not have to re-send the content. You should consider whether this is the behaviour you really want.

Here's a decent explanation of the various caching headers [http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/], or you can go to the RFC for the authoritative word, in more formal language [http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html]

There's usually little need to "update" the max-age value, unless you know ahead of time when the next version of the content will be generated server side, and using a fixed value for CC:max-age is a lot less intensive to generate the header than doing date calculations every time.

The Cache-Control header takes precedence over the Expires header for clients which understand Cache-Control (which is most of them, even ones which claim to be HTTP/1.0).

If your Expires header is being correctly generated, and the max-age value is not what you want, then your easiest solution might be to suppress CC: max age rather than correcting it. (http://wiki.nginx.org/HttpHeadersMoreModule)

Related Topic