Sinatra - 通过config.ru设置缓存控制标头

时间:2012-07-12 04:36:33

标签: ruby heroku sinatra rack jekyll

我目前正在Heroku的Cedar堆栈上运行Octopress(基于Jekyll)网站 - 代码存在于此处:https://github.com/elithrar/octopress

我想根据文件类型有选择地应用Cache-Control标头:

  • .html个文件的值为public, max-age=3600
  • .css|.js|.png|.ico(等)获取public, max-age=604800的值 - 或者,我想将此规则应用于/stylesheets', '/javascripts', '/imgs'目录中提供的任何内容。

使用了set :static_cache_control , [:public, :max_age => 3600]和只有vanilla cache_control :public, :max_age => 3600语句而没有运气。

我已设法在文章本身设置public, max-age=3600(例如/2012/lazy-sundays/),但未能将标题应用于CSS / JS(例如/stylesheets/screen.css

我的config.ru目前看起来像这样(已更新):

require 'bundler/setup'
require 'sinatra/base'

# The project root directory
$root = ::File.dirname(__FILE__)

class SinatraStaticServer < Sinatra::Base

  get(/.+/) do
    cache_control :public, :max_age => 7200
    send_sinatra_file(request.path) {404}
  end

  not_found do
    send_sinatra_file('404.html') {"Sorry, I cannot find #{request.path}"}
    cache_control :no_cache, :max_age => 0
  end

  def send_sinatra_file(path, &missing_file_block)
    file_path = File.join(File.dirname(__FILE__), 'public',  path)
    file_path = File.join(file_path, 'index.html') unless file_path =~ /\.[a-z]+$/i  
    File.exist?(file_path) ? send_file(file_path) : missing_file_block.call
  end

end

use Rack::Deflater

run SinatraStaticServer

2 个答案:

答案 0 :(得分:5)

以下是如何为静态资产设置长到期标头,以及为Heroku上的主要内容设置任意到期标头:

的Gemfile:

gem 'rack-contrib'

config.ru:

require 'rack/contrib'

get '*.html' do |page|
  # whatever code you need to serve up your main pages
  # goes here... use Rack::File I guess.
  page
end


# Set content headers for that content...
before do
  expires 5001, :public, :must_revalidate
end


# Assets in /static/stylesheets (domain.com/stylesheets) 
# are served by Rack StaticCache, with a default 2 year expiry.

use Rack::StaticCache, :urls => ["/stylesheets"], :root => Dir.pwd + '/static'

run Sinatra::Application

默认情况下,对于网址数组中列出的内容(静态/样式表,静态/图像等),您将获得2年到期日期。

你必须从/ public移动到/ static,否则你会不必要地使用Heroku的nginx配置(真正应用这些设置的正确位置......)。

我知道你说你试图不使用Rack Contrib,但这没有任何意义。使用一个小的90行库来完成这项工作没有任何害处https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/static_cache.rb

“正确”的方式是在可以配置nginx的环境中托管静态内容,第二种最好的方法是重命名静态文件路径,以便heroku忽略它,并使用rack static来提供带头的静态文件你想要的。

-

另外要明确的是,只需将公共文件夹重命名为其他内容即可通过路由执行此操作,并且正常的Sinatra会过期。但我会使用StaticCache,因为它不那么冗长。 (真正的问题是Heroku不会让nginx与您的应用程序讨论公开请求/,我相信。)

答案 1 :(得分:1)

我对Sinatra很少熟悉,但我认为这样的事情可以解决问题:

class SinatraStaticServer < Sinatra::Base
  before '*.html' do
    response.headers['Cache-Control'] = 'public, max-age=3600'
  end

  before %r{\.(css)|(js)|(png)|(ico)} do
    response.headers['Cache-Control'] = 'public, max-age=604800'
  end

  # ...
end

更新:当你说上面没有成功添加标题时,我进一步调查了它。我确定问题是Sinatra自动提供public/以外的文件,而不是通过应用程序,因此标题没有被添加。我的解决方案是将静态文件从public/移到public/public/并相应地调整send_sinatra_file

class SinatraStaticServer < Sinatra::Base
  # ...

  def send_sinatra_file(path, &missing_file_block)
    file_path = File.join(File.dirname(__FILE__), 'public/public',  path)
    file_path = File.join(file_path, 'index.html') unless file_path =~ /\.[a-z]+$/i
    File.exist?(file_path) ? send_file(file_path) : missing_file_block.call
  end

  # ...
end

我确认这可以在我的机器上运行。请注意,我在答案的第一部分中使用了response.headers['Cache-Control'],而不是您尝试的set :static_cache_control,但我认为只能在configure do块中运行一次。

另请注意,使用此当前设置,404匹配上述内容,例如nonexistant.png将提供404状态,其中仍然存在Cache-Control标头。我可以通过几种方式看到这一点,但我想你会这样做,所以我只是指出它,并指出你会按照自己喜欢的方式处理它。