1

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;
}
1

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)

  • Wow... good catch on that Pragma header... I removed that long ago, but it looks like there is some other code I have that is adding it. I didn't even notice. Thanks for that! Regarding max-age, the issue is that I'm caching both server-side and client-side. I have a server-side cache which caches all of the response headers as well, as that's what srcache does. However when I return that result, the Expires header is naturally still correct since it specifies a specific time in the future. The max-age is not, since it specifies a number of seconds. Is there no way to update it? – Brad Jul 9 '14 at 12:57
  • A site can calculate the appropriate number of seconds, and put that in the Cache-Control header, but I don't know how to do that with nginx. If you work that out though, you can give different instructions to your server-side cache using Cache-Control: s-maxage. – mc0e Jul 9 '14 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.