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