跳至内容 跳至搜索
命名空间
方法
E
F
H
M
N
S
包含的模块

实例公共方法

expires_in(seconds, options = {})

设置 Cache-Control 头部,会覆盖现有的指令。此方法还将确保 HTTP Date 头部以实现客户端兼容性。

默认情况下会发出 private 指令,因此中间缓存不得缓存响应。

选项

:public

如果为 true,则用 public 指令替换默认的 private 指令。

:must_revalidate

如果为 true,则添加 must-revalidate 指令。

:stale_while_revalidate

设置 stale-while-revalidate 指令的值。

:stale_if_error

设置 stale-if-error 指令的值。

:immutable

如果为 true,则添加 immutable 指令。

任何额外的键值对都会作为指令连接起来。有关支持的 Cache-Control 指令列表,请参阅 MDN 上的文章

示例

expires_in 10.minutes
# => Cache-Control: max-age=600, private

expires_in 10.minutes, public: true
# => Cache-Control: max-age=600, public

expires_in 10.minutes, public: true, must_revalidate: true
# => Cache-Control: max-age=600, public, must-revalidate

expires_in 1.hour, stale_while_revalidate: 60.seconds
# => Cache-Control: max-age=3600, private, stale-while-revalidate=60

expires_in 1.hour, stale_if_error: 5.minutes
# => Cache-Control: max-age=3600, private, stale-if-error=300

expires_in 1.hour, public: true, "s-maxage": 3.hours, "no-transform": true
# => Cache-Control: max-age=3600, public, s-maxage=10800, no-transform=true
# File actionpack/lib/action_controller/metal/conditional_get.rb, line 290
def expires_in(seconds, options = {})
  response.cache_control.delete(:no_store)
  response.cache_control.merge!(
    max_age: seconds,
    public: options.delete(:public),
    must_revalidate: options.delete(:must_revalidate),
    stale_while_revalidate: options.delete(:stale_while_revalidate),
    stale_if_error: options.delete(:stale_if_error),
    immutable: options.delete(:immutable),
  )
  options.delete(:private)

  response.cache_control[:extras] = options.map { |k, v| "#{k}=#{v}" }
  response.date = Time.now unless response.date?
end

expires_now()

设置 HTTP 1.1 Cache-Control 头部为 no-cache。这意味着资源将被标记为已过期,因此客户端必须始终重新验证。中间/浏览器缓存仍然可以存储该资源。

# File actionpack/lib/action_controller/metal/conditional_get.rb, line 309
def expires_now
  response.cache_control.replace(no_cache: true)
end

fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, cache_control: {}, template: nil)

在响应上设置 etaglast_modified 或两者,并在请求已是最新时渲染 304 Not Modified 响应。

选项

:etag

在响应上设置“弱”ETag 验证器。请参阅 :weak_etag 选项。

:weak_etag

在响应上设置“弱”ETag 验证器。指定了 If-None-Match 头部的请求,如果 ETag 完全匹配,可能会收到 304 Not Modified 响应。

弱 ETag 表示语义等价,而非逐字节相等,因此它们非常适合在浏览器缓存中缓存 HTML 页面。它们不能用于必须逐字节相同的响应,例如,在 PDF 文件中提供 Range 请求。

:strong_etag

在响应上设置“强”ETag 验证器。指定了 If-None-Match 头部的请求,如果 ETag 完全匹配,可能会收到 304 Not Modified 响应。

强 ETag 暗示完全相等——响应必须逐字节匹配。例如,这对于在大型视频或 PDF 文件中提供 Range 请求是必需的,或者对于与不支持弱 ETag 的某些 CDN 兼容是必需的。

:last_modified

在响应上设置“弱”最后更新验证器。后续请求指定了 If-Modified-Since 头部,如果 last_modified <= If-Modified-Since,可能会收到 304 Not Modified 响应。

:public

默认情况下,Cache-Control 头部为 private。如果希望您的应用程序可以被其他设备(例如代理缓存)缓存,请将此选项设置为 true

:cache_control

如果提供了此选项,将覆盖现有的 Cache-Control 头部。有关 Cache-Control 指令列表,请参阅 MDN 上的文章

:template

默认情况下,当前控制器/操作的模板摘要会包含在 ETags 中。如果操作渲染了另一个模板,您可以改用该模板的摘要。如果操作根本不渲染模板,您可以传递 template: false 来跳过任何尝试检查模板摘要的操作。

示例

def show
  @article = Article.find(params[:id])
  fresh_when(etag: @article, last_modified: @article.updated_at, public: true)
end

这将发送一个 304 Not Modified 响应,如果请求指定了匹配的 ETag 和 If-Modified-Since 头部。否则,它将渲染 show 模板。

您也可以只传递一个记录

def show
  @article = Article.find(params[:id])
  fresh_when(@article)
end

etag 将设置为该记录,last_modified 将设置为该记录的 updated_at

您也可以传递一个响应 maximum 的对象,例如记录集合

def index
  @articles = Article.all
  fresh_when(@articles)
end

在这种情况下,etag 将设置为集合,last_modified 将设置为 maximum(:updated_at)(最近更新记录的时间戳)。

传递记录或集合时,您仍然可以指定其他选项,例如 :public:cache_control

def show
  @article = Article.find(params[:id])
  fresh_when(@article, public: true, cache_control: { no_cache: true })
end

上面的代码将在响应中设置 Cache-Control: public, no-cache

渲染与控制器/操作默认模板不同的模板时,您可以指示要在 ETag 中包含哪个摘要

before_action { fresh_when @article, template: "widgets/show" }
# File actionpack/lib/action_controller/metal/conditional_get.rb, line 137
def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, cache_control: {}, template: nil)
  response.cache_control.delete(:no_store)
  weak_etag ||= etag || object unless strong_etag
  last_modified ||= object.try(:updated_at) || object.try(:maximum, :updated_at)

  if strong_etag
    response.strong_etag = combine_etags strong_etag,
      last_modified: last_modified, public: public, template: template
  elsif weak_etag || template
    response.weak_etag = combine_etags weak_etag,
      last_modified: last_modified, public: public, template: template
  end

  response.last_modified = last_modified if last_modified
  response.cache_control[:public] = true if public
  response.cache_control.merge!(cache_control)

  head :not_modified if request.fresh?(response)
end

http_cache_forever(public: false)

缓存或执行块。缓存应该永远不会过期。

当您有一个永不改变的 HTTP 响应,并且希望浏览器和代理无限期地缓存它时,可以使用此方法。

  • public:默认情况下,HTTP 响应是私有的,仅缓存在用户的 Web 浏览器中。要允许代理缓存响应,请将其设置为 true,以表明它们可以向所有用户提供缓存的响应。

# File actionpack/lib/action_controller/metal/conditional_get.rb, line 321
def http_cache_forever(public: false)
  expires_in 100.years, public: public, immutable: true

  yield if stale?(etag: request.fullpath,
                  last_modified: Time.new(2011, 1, 1).utc,
                  public: public)
end

must_understand()

must-understand 指令添加到 Cache-Control 头部,这表示缓存必须理解收到的响应状态码的语义,否则就丢弃响应。

当返回带有新颖或不常见状态码的响应时,而这些状态码可能无法被旧的缓存正确解释,这一点尤其有用。

示例

def show
  @article = Article.find(params[:id])

  if @article.early_access?
    must_understand
    render status: 203 # Non-Authoritative Information
  else
    fresh_when @article
  end
end
# File actionpack/lib/action_controller/metal/conditional_get.rb, line 355
def must_understand
  response.cache_control[:must_understand] = true
  response.cache_control[:no_store] = true
end

no_store()

设置 HTTP 1.1 Cache-Control 头部为 no-store。这意味着资源不得存储在任何缓存中。

# File actionpack/lib/action_controller/metal/conditional_get.rb, line 331
def no_store
  response.cache_control.replace(no_store: true)
end

stale?(object = nil, **freshness_kwargs)

在响应上设置 etag 和/或 last_modified,并将其与请求进行比较。如果请求与提供的选项不匹配,则认为它已过期,并且应该从头开始渲染响应。否则,它就是最新的,并发送 304 Not Modified

选项

有关支持的选项,请参阅 fresh_when

示例

def show
  @article = Article.find(params[:id])

  if stale?(etag: @article, last_modified: @article.updated_at)
    @statistics = @article.really_expensive_call
    respond_to do |format|
      # all the supported formats
    end
  end
end

您也可以只传递一个记录

def show
  @article = Article.find(params[:id])

  if stale?(@article)
    @statistics = @article.really_expensive_call
    respond_to do |format|
      # all the supported formats
    end
  end
end

etag 将设置为该记录,last_modified 将设置为该记录的 updated_at

您也可以传递一个响应 maximum 的对象,例如记录集合

def index
  @articles = Article.all

  if stale?(@articles)
    @statistics = @articles.really_expensive_call
    respond_to do |format|
      # all the supported formats
    end
  end
end

在这种情况下,etag 将设置为集合,last_modified 将设置为 maximum(:updated_at)(最近更新记录的时间戳)。

传递记录或集合时,您仍然可以指定其他选项,例如 :public:cache_control

def show
  @article = Article.find(params[:id])

  if stale?(@article, public: true, cache_control: { no_cache: true })
    @statistics = @articles.really_expensive_call
    respond_to do |format|
      # all the supported formats
    end
  end
end

上面的代码将在响应中设置 Cache-Control: public, no-cache

渲染与控制器/操作默认模板不同的模板时,您可以指示要在 ETag 中包含哪个摘要

def show
  super if stale?(@article, template: "widgets/show")
end
# File actionpack/lib/action_controller/metal/conditional_get.rb, line 236
def stale?(object = nil, **freshness_kwargs)
  fresh_when(object, **freshness_kwargs)
  !request.fresh?(response)
end