HTTP 302 Redirects + XMLHttpRequests = ARGH!!1
Posted by Richard White Mon, 10 Apr 2006 21:59:40 GMT
Best I can tell the problem is that XMLHttpRequests handle 302 redirects exactly the same way that a regular request would, which in most cases results in that redirect destination page being embedded into an element on the existing page. According to the spec the user agent, aka your browser, will automatically fetch the redirected page and return to you what looks like a perfectly valid response. Therefore you have no knowledge that this is not the page you originally asked for and no way to figure that out.
I’ve seen a code snippet that uses 302 status code handler with your Prototype Ajax requests to set the window location. I’m not sure how that code ever worked, since all my testing shows that you will be redirected silently without the 302 handler ever being called.
The best and only solution I could come up with was to override the default Rails redirect_to method to return javascript (using the PrototypeHelper in Rails 1.1) to redirect the current page using the document.location property:
class ActionController::Base
alias_method :base_redirect_to, :redirect_to
def redirect_to(options={}, *parameters_for_method_reference)
if request.xhr?
redirect_url = url_for(options, *parameters_for_method_reference)
render(:update) { |page| page.redirect_to(redirect_url) }
else
base_redirect_to options
end
end
end
I put the preceding code into lib/redirect_to_patch.rb and added require 'redirect_to_patch' to config/environment.rb. This method has its drawbacks, most notably that if you have evalScripts set to false it will not work! Luckily Rails defaults evalScripts to true so if you are turning that off I assume you know what you are doing. Also if you are automatically updating a page element from the AJAX request you will see the javascript redirect code placed into the page just before the page is redirected.
This is the only sane solution I’ve come up with to solve this problem easily and transparently across the application. If anyone has a better way please let me know.
Hi, the ”...redirect code placed into the page…” goes away if you don’t have an update or insert in the request. (ie let the javascript do the insert or update)
Right, perhaps I wasn’t clear enough about that point.
For urls that have multiple parameters in them ( /controller/action/id?foo=1&bar=2 ) the ampersands get screwed up with the code above. Replacing:
page.redirect_to(redirect_url)
with:
page << “window.location.href = ’#{redirect_url}’;”
appears to solve this problem.