Response: Last-modified (When the resource was last changed)
Request: If-modified-since (Is the resource newer than the last time I saw it?)
Pros
Reduces response bandwidth
You control when the browser uses its cache
Reduces Server Load (but not automatically)
Cons
Browser sends a request every time
ETag / If-None-Match
Like Last-modified + If-modified-since - Instead of checking if the content is newer, it checks if the content is different
Response includes ETag
Subsequent request includes If-None-Match (Is the resource different than the last time I saw it?)
Return HTTP Code 304-Not-Modified
Cache-Control
Additional caching info for the browser
Response includes Cache-Control
Semicolon-separated list of directives:
max-age: allowed to be cached for this long
You’re basically telling the browser “Don’t even bother checking for a new version of this resource.” for some amount of time. (Using max-age, it will hit server until then)
Pros:
Doesn’t even hit the server when cache is still fresh.
Cons:
Browser may show out-of-date content
You can’t usually know when the resource will change in advance but what you can do is you can decide ‘I’m okay with letting users see stale data for a certain amount of time.’ if the trade-off is faster performance for users and lower load on the server,
—
How to use ETag in Rails
Rack::ETag and Rack::ConditionalGet are a wonderful pair of rack middleware.
Generates ETag based on an MD5 digest of the response body.
Rack::ConditionalGet compares If-None-Match with ETag
Converts 200 OK with body to 304 Not Modified without body. (-> Less bandwidth consume)
Saves network time with zero effort.
Does not save server time (renders the response to make and compare the digest)
stales? and fresh_when
stales?
Save server time by not rendering views (Generate an ETag without having to take the time to render the entire view)
Set ETag, Last-Modified, and Cache-Control headers
To set ETag, Rails calls ActiveSupport::Cache.expand_cache_key, then makes an MD5 digest of the result
Cache key for a student looks like: 'students/25-20140630120340'
Pass any object that responds to cache_key
Also works for an array.
Last-modified is updated_at timestamp by default. (If it is an array, you must tell it what value is Last-Modified)
def show
@student = Student.find(params[:id])
if stale?(last_modified: @student.updated_at, etag: @student)
respond_to do |wants|
# rnder different formats
end
end
end
fresh_when
def show
@student = Student.find(params[:id])
fresh_when last_modified: @student.updated_at,
etag: @student
end
Using stale? and fresh_when when in new and edit
def new
@student = Student.new
fresh_when last_modified: @student.updated_at,
etag: [@student, form_authenticity_token]
end
def edit
@student = Student.find(params[:id])
fresh_when last_modified: @student.updated_at,
etag: [@student, form_authenticity_token]
end
Using stale? and fresh_when with Pagination
def index
@students = Student.order(:name).page(params[:page])
count = Student.count
max_updated_at = Student.maximum(:updated_at).try(:utc).try(:to_s, :number)
fresh_when etag: "students/all-#{count}-#{max_updated_at}"
end
Propagate updated_at to Owning Objects
class Enrollment < ActiveRecord::Base
belongs_to :course, touch: true
belongs_to :student, touch: true
end
Browser Caching
Apply for GET request only
Response: Last-modified (When the resource was last changed) Request: If-modified-since (Is the resource newer than the last time I saw it?)
Pros
Reduces response bandwidth You control when the browser uses its cache Reduces Server Load (but not automatically)
Cons
Browser sends a request every time
ETag / If-None-Match
Like Last-modified + If-modified-since - Instead of checking if the content is newer, it checks if the content is different
Response includes ETag Subsequent request includes If-None-Match (Is the resource different than the last time I saw it?)
Return HTTP Code 304-Not-Modified
Cache-Control
You’re basically telling the browser “Don’t even bother checking for a new version of this resource.” for some amount of time. (Using max-age, it will hit server until then)
Pros:
Doesn’t even hit the server when cache is still fresh.
Cons:
Browser may show out-of-date content
You can’t usually know when the resource will change in advance but what you can do is you can decide ‘I’m okay with letting users see stale data for a certain amount of time.’ if the trade-off is faster performance for users and lower load on the server,
—
How to use ETag in Rails
Rack::ETag
andRack::ConditionalGet
are a wonderful pair of rack middleware.Rack::ETag
provides build-in, automaticETag
generation.Rack::ConditionalGet
comparesIf-None-Match
with ETagstales?
andfresh_when
stales?
ActiveSupport::Cache.expand_cache_key
, then makes an MD5 digest of the resultcache_key
updated_at
timestamp by default. (If it is an array, you must tell it what value is Last-Modified)fresh_when
Using
stale?
andfresh_when
when innew
andedit
Using
stale?
andfresh_when
with PaginationPropagate
updated_at
to Owning Objects