简体   繁体   中英

Rails respond_to processes XML but caches HTML

This might be a bit of a tricky one. The 'root' page of my site is rendered by the posts#index action. To support rss and html, I have a respond_to block that looks like:

 respond_to do |wants|
  wants.html 
  wants.xml {
    render :layout => false;
    response.headers["Content-Type"] = "application/xml; charset=utf-8"
  }
end

I also have a 'caches_page' set on the index page.

If someone comes to the site in a browser and just requests "/", then they get served the html version of the page, and Rails also writes a cached page for index.html

There isn't really any way to request "/" with a format of XML, but if I hit "/posts.xml" it renders XML and caches posts.xml (similarly if I hit "/posts" or "/posts.html" it will cache posts.html). That all works just fine.

Now for the tricky bit. If something requests "/" but has an accept header like:

Accept: text/xml

Then Rails will process it as XML (probably correct), but CACHES it as html, destroying my cache. The next visitor to the site will be forever server an html file that actually contains XML. Here is the Rails log message proving this is happening:

Started GET "/" for 127.0.0.1 at 2010-11-30 20:47:27 +0000
  Processing by PostsController#index as XML
  Post Load (1.4ms)  SELECT "posts".* FROM "posts" WHERE ...
Rendered posts/index.xml.rxml (243.8ms)
Write page /..../index.html (0.6ms)
Completed 200 OK in 423ms (Views: 244.8ms | ActiveRecord: 1.4ms)

Is this a feature or a bug?

Better, has anyone any idea how to fix it so that it caches the file as .xml when it processes it as XML?

Which version of Rails are you using? You might want to upgrade, if your on an older version. (the .rxml extension is old afaik)

That looks like a bug to me. I remember having similar problems two years back (IE says it accepts XLS, but it doesn't mention HTML).

I believe it was fixed in recent versions.

I used to work around it by modifying the HTTP_ACCEPT header for IE. (digs up some old code)

request.env["HTTP_ACCEPT"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" if request.env["HTTP_USER_AGENT"].include?('MSIE')

But I wouldn't recommend doing something like this before you tried the more sane options.

If you change your request for XML to point at /.xml then I think the cache should differentiate between the HTML and XML as they will be different URLs.

I had this same problem with a Backbone.js app. If I navigated from / to /tasks then hit the back button Chrome would serve the cached HTML version of /tasks , instead of loading the JSON version. The fix was to make sure my Backbone models were calling /tasks.js instead of just /tasks . Rails 3.x routes take the format as an optional part at the end of the URL, which helps any caches between your browser and server differentiate between different formats if they aren't looking at the accept/content-type headers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM