8

My server returns the following headers:

Cache-Control:no-cache
Connection:keep-alive
Date:Thu, 07 Jul 2011 10:41:57 GMT
Expires:Thu, 01 Jan 1970 00:00:01 GMT
Last-Modified:Thu, 07 Jul 2011 08:06:32 GMT
Server:nginx/0.8.46`

I want the content I'm serving not to be cached, so I'm looking for a way to return a Last-Modified header that contains the date-time when the request was originated. Something like now()...

Luca Gibelli
  • 2,731
  • 1
  • 22
  • 30
evilpenguin
  • 781
  • 3
  • 9
  • 16

3 Answers3

10

"I want the content I'm serving not to be cached" : You can turn off If-Modified-Since request header checking with if_modified_since off; directive. if_modified_since doc

And about Last-Modified header: You can turn it off with add_header Last-Modified "";

Casual Coder
  • 1,216
  • 1
  • 11
  • 12
  • 1
    You can't turn off headers with [add_header](http://wiki.nginx.org/HttpHeadersModule#add_header), you can only add them. From the entry: Note that it just appends a new header entry to the output header list. So you can't use this directive to rewrite existing headers like Server. Use the [headers_more](http://wiki.nginx.org/NginxHttpHeadersMoreModule) module for it. – kolbyjack Jul 07 '11 at 14:16
  • I've checked it with `curl -D` and after adding `add_header Last-MOdified "";` to my nginx.conf, `Last-Modified` header is no longer there in dump file. – Casual Coder Jul 07 '11 at 16:54
  • 1
    Wow, looking at the source, Cache-Control and Last-Modified are special cased and will be set instead of having an extra entry added. It seems the wiki needs to be updated. – kolbyjack Jul 07 '11 at 18:03
  • 1
    I was wrong again, Cache-Control is special cased, but it doesn't overwrite, it just has to be added in a special way. Only Last-Modified sets the header instead of adding a new one. – kolbyjack Jul 07 '11 at 18:16
  • Good to know, could you point me to a file ? Is it in `src/http/ngx_http_header_filter_module.c` ? – Casual Coder Jul 07 '11 at 18:33
  • Yes, if you look at ngx_http_headers_add in that file, you'll see that it doesn't do the normal add for headers in ngx_http_set_headers, defined at the top of the file. For Last-Modified, it calls ngx_http_set_last_modified, and for Cache-Control, it calls ngx_http_add_cache_control. – kolbyjack Jul 07 '11 at 19:06
  • Ok, I'm greping source for identifiers that you are talking about and I've found none of them. I've got things like `ngx_http_headers_out` and others. We are talking about two different nginx versions. I've got 1.0.4, and what is yours? – Casual Coder Jul 07 '11 at 19:19
  • Oh, sorry, I misread. You need to look in src/http/modules/ngx_http_headers_filter_module.c . The filenames are similar, and I failed to notice the lack of /modules. – kolbyjack Jul 07 '11 at 19:28
  • Ok, I've got it. I failed at greping previously, If I've done it recursively I would have found it. Thanks for walking me through it. – Casual Coder Jul 07 '11 at 19:43
6

You may want to make it look like a file is always modified:

add_header Last-Modified $date_gmt;
if_modified_since off;
etag off;

As for the last line, if you really want to hide a true last-modified date, then you must hide the ETag header too since it leaks timestamps.

sanmai
  • 531
  • 5
  • 19
0

I've honestly spent a whole day on this and not closer to getting Nginx to play along properly especially with the way Nginx incorrectly formats the Last-Modified: Date header which is not within the RFC's for a Last-Modified header.

I found this solution however which, if you are using PHP, works just fine and can be tweaked as you need. Hope it helps. Just include this at the very top of your .php pages before the rest of your code.

<?php
//get the last-modified-date of this very file
$lastModified=filemtime(__FILE__);
//get a unique hash of this file (etag)
$etagFile = md5_file(__FILE__);
//get the HTTP_IF_MODIFIED_SINCE header if set
$ifModifiedSince=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false);
//get the HTTP_IF_NONE_MATCH header if set (etag: unique file hash)
$etagHeader=(isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : false);

//set last-modified header
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $lastModified)." GMT");
//set etag-header
//header("Etag: $etagFile");
header("ETag: \"$etagFile\"");
//make sure caching is turned on
header('Cache-Control: private, must-revalidate, proxy-revalidate, max-age=3600');

//check if page has changed. If not, send 304 and exit
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])==$lastModified || $etagHeader == $etagFile)
{
       header("HTTP/1.1 304 Not Modified");
       header("Vary: Accept-Encoding");
       exit;
}
?>

Then test your site at redbot.org and www.hscripts.com

UPDATE:

  1. Added sending the vary header with the 304 not modified response (required)
  2. Modified Cache:Control header max-age can be tweaked to your own needs.
  3. To give credit where it is due, I found the solution here and tweaked it slightly - https://css-tricks.com/snippets/php/intelligent-php-cache-control/
MitchellK
  • 149
  • 8