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

发布于 2024-11-06 19:20:40 字数 1250 浏览 0 评论 0原文

我有一个基于 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 ]

I have a JSON and XML based API that needs to be page cached. I have setup my routes on the api to include the format as part of the URL, such that URL's like this work:

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

The problem I am seeing is that in the server's public folder, the files are being saved as xml.xml and json.json, and this causes cache misses the next time the URL is accessed.

Is there a way to either:

  1. Turn off the auto extension generation so that they are saved without an extension at all? (EX: RAILS_ROOT/public/foo/1/bar/2/json)
  2. Force all the extensions to be .html for every call. (EX: RAILS_ROOT/public/foo/1/bar/2/json.html)

Either of these would cause my server to return the cached file instead of a miss. How can I do this?

EDIT:
Somebody asked for the relevant route:

scope '(foo/:foo_id)', :foo_id => /\d+/ do
  get '/bar/:bar_id/:format' => 'bars#show', :bar_id => /\d+/, :format => /json|xml|html/
end

SOLUTION:
While I was looking for an official way to make this happen using the built in page caching support, I ended up just using an after filter and my own page cache method, as suggested by 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 ]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你不是我要的菜∠ 2024-11-13 19:20:40

你可以这样做:

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>

You can do that like this:

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

When http://example.com/foo/1/bar/2/json is accessed, it will write page to cache (RAILS_ROOT/public/foo/1/bar/2/json.html)

And if you get http://example.com/foo/1/bar/2/json again, you receive RAILS_ROOT/public/foo/1/bar/2/json.html, but your http server(Apache?) should know about content type of this files.

Otherwise content type will set to 'text/html'

UPDATE

To you .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>
蓝色星空 2024-11-13 19:20:40

在您的 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

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

In your application.rb configuration block try adding:

config.action_controller.page_cache_extension = '.html'

It should ignore the extension calculated from the request, and always use this.
You could also try using this with an empty string instead.

EDIT: actually this won't work because this only sets a default. If the request has an extension (in your case, concluded from :format) it will be used.

I suggest changing :format in your routes to something else, that rails will not give special meaning to, like :fmt. Then rails should not add the extension and default to '.html'.

EDIT2: If you have to use :format you can 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

Notice the comment sign I've added before 'unless'. This is the part that overrides the default from my first answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文