The presence of an Expires field does not imply that the original resource will
change or cease to exist at, before, or after that time.
Think carefully before setting up a time when a resource should be
regarded as stale. Most of the time we can determine an expected
lifetime from "now" (that is, the
time of the request). We do not recommend hardcoding the expiration
date, because when we forget that we did it, and the date arrives, we
will serve already expired documents that cannot be cached. If a
resource really will never expire, make sure to follow the advice
given by the HTTP specification:
To mark a response as "never expires," an origin server sends an Expires date
approximately one year from the time the response is sent. HTTP/1.1 servers SHOULD
NOT send Expires dates more than one year in the future.
For example, to expire a document half a year from now, use the
following code:
$r->header_out('Expires',
HTTP::Date::time2str(time + 180*24*60*60));
or:
$r->header_out('Expires',
Apache::Util::ht_time(time + 180*24*60*60));
The latter method should be faster, but it's
available only under mod_perl.
A very handy alternative to this computation is available in the
HTTP/1.1 cache-control mechanism. Instead of setting the
Expires header, we can specify a delta value in a
Cache-Control header. For example:
$r->header_out('Cache-Control', "max-age=" . 180*24*60*60);
This is much more processor-economical than the previous example
because Perl computes the value only once, at compile time, and
optimizes it into a constant.
As this alternative is available only in HTTP/1.1 and old cache
servers may not understand this header, it may be advisable to send
both headers. In this case the Cache-Control
header takes precedence, so the Expires header is
ignored by HTTP/1.1-compliant clients. Or we could use an
if...else clause:
if ($r->protocol =~ /(\d\.\d)/ && $1 >= 1.1) {
$r->header_out('Cache-Control', "max-age=" . 180*24*60*60);
}
else {
$r->header_out('Expires',
HTTP::Date::time2str(time + 180*24*60*60));
}
Again, use the Apache::Util::ht_time( )
alternative instead of HTTP::Date::time2str( ) if
possible.
If the Apache server is restarted regularly (e.g., for log rotation),
it might be beneficial to save the Expires header
in a global variable to save the runtime computation overhead.
To avoid caching altogether, call:
$r->no_cache(1);
which sets the headers:
Pragma: no-cache
Cache-control: no-cache
This should work in most browsers.
Don't set Expires with
$r->header_out if you use
$r->no_cache, because header_out(
) takes precedence. The problem that remains is that there
are broken browsers that ignore Expires headers.