Вопрос

If I send a remote: true request to our subdomain controller, our layout renders (which it shouldn't)

Having tested the request.xhr? method in the action, it's returning nil (not the true / false) that you'd expect. This works for non-CORS ajax. It only stops working with CORS-ajax (for subdomain)


Here's the code:

#app/views/controller/view.html.haml
= link_to "test", new_user_session_url, remote: :true

#routes
new_user_session_path   GET  /login(.:format)    admin/users/sessions#new {:subdomain=>"test"}

The response occurs & we get a layout

We want no layout, which works without CORS:

#app/controllers/application_controller.rb
layout :layout_select

  def layout_select
    if request.xhr?
      false
    else
      devise_controller? ? "admin" : "application"
    end
  end

We have CORS policy set up & working. However, it seems our CORS-request is not being treated as xhr. Any ideas?

Это было полезно?

Решение

In light of the comments from Mike Campbell, I was able to determine that CORS requests are not treated as ajax (xhr) by default

The problem lies in the headers which are passed on an Ajax request. Standard ajax passes the following header:

  #actionpack/lib/action_dispatch/http/request.rb
  def xhr?
       @env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/ 
  end

This is passed with a "naked" Ajax request, which allows the xhr? method to return either true or false. The issue is in a CORS ajax call, this header is not passed. I don't know why, but it just sends an ORIGIN header instead

The proposed fix from Github suggested to include this:

 uri.host != @env['HTTP_HOST'] || uri.scheme != @env['rack.url_scheme'] || uri.port != @env['HTTP_PORT'].to_i

This would basically return a boolean response based on whether the request was from the same domain as the script. Although this was prevented for being unsafe, it lead me to two fixes:

  1. Append a new cors? method to the Rails core
  2. Send the http_x_requested_with header through a CORS request

Considering we are just trying to access a subdomain with the request, we felt that editing the Rails core was slightly overkill, although right. Instead, we found that using the inbuilt headers argument in jquery would help:

$.ajaxSetup({ headers: {"X-Requested-With": "XMLHttpRequest"}});

Whilst this works, I am eager to hear about any security issues it may present. And plus, whether we can access json and other formats with it

Другие советы

It's because of the Same-Origin Policy. Please read carefully this article: HTTP access control (CORS).

The possible solutions are:

  • make simple request – instead of remote: true do usual form post or maybe $.getJSON() will work (not sure).
  • implement preflight request – you'll need to implement on your server response for OPTIONS request.
  • if you need to maintain cookies then you'll also need to write custom ajax code, eg. $.ajax({url: a_cross_domain_url, crossDomain: true, xhrFields: {withCredentials: true}}); and return some specific headers from the server.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top