Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XMLHttpRequest No 'Access-Control-Allow-Origin' header is present on the requested resource

So there are a handful of questions on StackOverflow addressing this error, but of the 10-15 I checked, I could not find a solution to my exact problem.

I am running an Angular app (port 9000) and a Rails app (port 3000) on a remote server. The angular app sends requests to the rails app via a post request.

When a request is made, the Javascript console shows this error message:

XMLHttpRequest cannot load http://0.0.0.0:3000/api/query. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://10.241.16.159:9000' is therefore not allowed access. 

From what I've read, I need to change something about my Rails app so that it can accept connection from other servers (which seems odd because both apps are running on the same ec2 instance).

I've tried adding a line like

  skip_before_filter :verify_authenticity_token

to my controller in rails, but this seems to have no effect.

How can I resolve this error?

like image 654
johncorser Avatar asked Jul 30 '14 19:07

johncorser


2 Answers

In app/controllers/application_controller.rb:

before_filter :add_allow_credentials_headers

def add_allow_credentials_headers                                                                                                                                                                                                                                                        
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#section_5                                                                                                                                                                                                      
  #                                                                                                                                                                                                                                                                                       
  # Because we want our front-end to send cookies to allow the API to be authenticated                                                                                                                                                                                                   
  # (using 'withCredentials' in the XMLHttpRequest), we need to add some headers so                                                                                                                                                                                                      
  # the browser will not reject the response                                                                                                                                                                                                                                             
  response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] || '*'                                                                                                                                                                                                     
  response.headers['Access-Control-Allow-Credentials'] = 'true'                                                                                                                                                                                                                          
end 

def options                                                                                                                                                                                                                                                                              
  head :status => 200, :'Access-Control-Allow-Headers' => 'accept, content-type'                                                                                                                                                                                                         
end

In config/routes.rb:

match '*any' => 'application#options', :via => [:options]

Note, this is responding to OPTIONS requests which you will need if your Angular front-end is performing POST requests. The bit I am doing with Access-Control-Allow-Credentials is for my app so cookies are sent from the front-end.

I highly suggest that you read the docs in that mozilla link in my code above. It has a very thorough explanation of CORS. You may find that the code above is too permissive for your purposes.

like image 163
Skippy Jones Avatar answered Nov 14 '22 20:11

Skippy Jones


In case you've not read up about it yet, let me give you some idea as to what the issue is...

You've got a problem with the CORS policy of your apps

--

CORS (Corss Origin Resource Sharing)

When you access an endpoint on another server with XHR (XML HTTP REQUEST), your application (although I'm not sure how) will by default DENY access to the requesting resource.

The reason why this happens is to ensure only certain data / resources are made available via XHR, and is why it's used mainly for the likes of APIs.

enter image description here

--

rack-CORS

Anyway, you need to allow access to your Java application inside your Rails application - which I personally would recommend with the rack-CORS gem:

#Gemfile
gem 'rack-cors'

#config/application.rb
config.middleware.use Rack::Cors do
   allow do
     origins '*'
     resource 'api/jquery', :headers => :any, :methods => [:get, :post]
   end
end

This will "allow" the requests from your different applications, fixing the issue for you.

like image 26
Richard Peck Avatar answered Nov 14 '22 21:11

Richard Peck