Rails页面缓存和自动扩展存在问题

6

我有一个基于JSONXML的API需要进行页面缓存。我已经在API上设置了路由,将格式作为URL的一部分包括在内,这样像这样的URL就可以工作:

http://example.com/foo/1/bar/2/xml
http://example.com/foo/1/bar/2/json

我看到的问题是,在服务器的public文件夹中,文件被保存为xml.xmljson.json,这会导致下次访问URL时缓存未命中。
有没有办法:
1.关闭自动生成扩展名的功能,使其完全不带扩展名?(例如:RAILS_ROOT/public/foo/1/bar/2/json
2.强制所有调用的扩展名都是.html。(例如:RAILS_ROOT/public/foo/1/bar/2/json.html
任何一种方法都会导致我的服务器返回缓存文件而不是未命中。我该怎么做?
编辑: 有人要求相关路由:
scope '(foo/:foo_id)', :foo_id => /\d+/ do
  get '/bar/:bar_id/:format' => 'bars#show', :bar_id => /\d+/, :format => /json|xml|html/
end
解决方案:
当我在寻找一种官方方法来使用内置的页面缓存支持时,最终我采用了一个过滤器和自己的页面缓存方法,正如Anton所建议的那样。
# application_controller.rb
def cache_api_page
  if REDACTEDServer::Application.config.action_controller.perform_caching
    self.class.cache_page(response.body, request.path, '')
    puts "CACHED PATH: #{request.path}"
  end
end

# bar_controller.rb
 after_filter :cache_api_page, :only => [ :show, :index ]

你尝试过在API中使用“正常”的约定吗?例如..bar/2.xml和../bar/2.json。 - oma
这不是API设计,我需要使其向后兼容,因此无法更改为.ext方法。但在我看来,这会导致URL变得丑陋。 - coneybeare
你能发布一下你的路由示例吗? - Jack Chu
2个回答

3
你可以这样做:
class FooController < ApplicationController

  after_filter(:only => :show, :if => Proc.new { |c| c.request.format.json? }) do |controller|
    controller.class.cache_page(controller.response.body, controller.request.path, '.html')
  end

end

当访问 http://example.com/foo/1/bar/2/json 时,将把页面写入缓存 (RAILS_ROOT/public/foo/1/bar/2/json.html)。
如果再次获取 http://example.com/foo/1/bar/2/json,则会接收到 RAILS_ROOT/public/foo/1/bar/2/json.html,但是您的 HTTP 服务器(Apache?)需要了解这些文件的内容类型。
否则,内容类型将设置为'text/html'。 更新 对于您的 .htaccess 文件。
<FilesMatch "\/json$">
<IfModule mod_headers.c>
  Header set Content-Type "text/json"
</IfModule>
</FilesMatch>


<FilesMatch "\/xml$">
<IfModule mod_headers.c>
  Header set Content-Type "text/xml"
</IfModule>
</FilesMatch>

这似乎可行,但需要在我的应用程序和方法中编写大量代码。在看到其他内容之前,我将暂时不给出答案。关于Apache,请求的格式与上面列出的URL完全相同,因此,除非我让请求具有.xml或.json扩展名,否则Apache不知道它是xml还是json文件。这就是为什么我需要这样做的原因。 - coneybeare
你的更新在Rails上不起作用,因为Rails和Passenger Apache设置会忽略htaccess。不过你最初的回答仍然有效。 - coneybeare

0
在你的 application.rb 配置块中尝试添加以下内容:
config.action_controller.page_cache_extension = '.html'

它应该忽略从请求中计算出来的扩展名,并始终使用此扩展名。 您也可以尝试将其与空字符串一起使用。

编辑:实际上这不起作用,因为它只设置了一个默认值。如果请求有一个扩展名(在您的情况下,从:format推断出来),它将被使用。

我建议在您的路由中更改:format为其他内容,Rails不会赋予特殊含义,例如:fmt。然后Rails就不会添加扩展名并默认为“.html”。

编辑2:如果您必须使用:format,则可以monkeypatch Rails:

ActionController::Caching::Pages::ClassMethods
  private
  def page_cache_file(path)
    name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/'))
    name << page_cache_extension #unless (name.split('/').last || name).include? '.'
    return name
  end
end

注意我在“unless”之前添加的注释符号。这是覆盖我第一个答案中默认设置的部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接