Often, the ETag is a hash of the response body, but it can be anything that is likely to
change when the body does. Another common method used for static content is to
use some combination of the file??™s inode number, last-modified time, and size; this is
very efficient because all of that information can be determined with a stat(2)
syscall. Of course, this method breaks down in clusters (where the static files might
span filesystems) or when serving dynamic content.
Rails has built-in support for transparently generating ETags. The method used is the
???simplest thing that could possibly work???; it is generic because it makes no assumptions
about the structure or semantics of an application. Its implementation is simple
enough that it can be shown here:
def handle_conditional_get!
if body.is_a?(String) &&
(headers['Status'] ? headers['Status'][0..2] == '200' : true) &&
!body.empty?
self.headers['ETag'] ||= %("#{Digest::MD5.hexdigest(body)}")
self.headers['Cache-Control'] = 'private, max-age=0, must-revalidate' if
headers['Cache-Control'] == DEFAULT_HEADERS['Cache-Control']
if request.headers['HTTP_IF_NONE_MATCH'] == headers['ETag']
self.headers['Status'] = '304 Not Modified'
self.body = ''
end
end
end
On each request with a 200 OK response, Rails generates an MD5 hash of the
response body and sets it as the ETag (unless one has already been set; this allows
you to provide custom ETags simply by setting them).
Pages:
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346