我有一个基于JSON
和XML
的API,需要页面缓存。我已经在 api 上设置了我的路由以将格式作为 URL 的一部分包含在内,这样 URL 就像这样工作:
http://example.com/foo/1/bar/2/xml
http://example.com/foo/1/bar/2/json
我看到的问题是,在服务器的public
文件夹中,文件被保存为xml.xml
和json.json
,这会导致下次访问URL时缓存未命中。
有没有办法:
- 关闭自动扩展生成,以便在没有扩展名的情况下保存它们?(例如:
RAILS_ROOT/public/foo/1/bar/2/json
) - 强制每次呼叫
.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
解决方案:当我正在寻找一种使用内置页面缓存支持的官方方法来实现这一目标时,我最终只使用了 after 过滤器和我自己的页面缓存方法,正如 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 ]
你可以这样做:
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?)应该知道这个文件的内容类型。
否则,内容类型将设置为"文本/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>
在您的 application.rb 配置块中尝试添加:
config.action_controller.page_cache_extension = '.html'
它应该忽略从请求计算的扩展,并始终使用它。您也可以尝试将其与空字符串一起使用。
编辑:实际上这不起作用,因为这只设置了一个默认值。如果请求具有扩展名(在您的情况下,从 :format 结束),则将使用它。
我建议将路由中的 :format 更改为其他内容,这样 rails 不会赋予特殊含义,例如 :fmt。然后 rails 不应该添加扩展名并默认为".html"。
编辑2:如果你必须使用:format,你可以猴子补丁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
请注意我在"除非"之前添加的评论符号。这是覆盖我第一个答案的默认值的部分。