Cross domain AJAX Request with Sinatra not working - sending JSON with jQuery.ajax

On my server in my sinatra app I have the following settings:

before do
  headers 'Access-Control-Allow-Origin' => '*',
          'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST'],
          'Access-Control-Allow-Headers' => ['Content-Type', 'Accept', 'X-Requested-With', 'access_token']

  env['rack.errors'] = error_logger
end

In my frontend app I perform the following http request:

$.ajax({
        type: "POST",
        url: "http://findaspot.multimediatechnology.at/api/",
        data: json,
        dataType: "json",
        success: function (data) {
            console.log('Success!');
            console.log(data);
        },
        error: function(xhr, status, error) {
            var err = eval("(" + xhr.responseText + ")");
            alert(err.Message);
        }
    })

I always get this error message:

XMLHttpRequest cannot load http://findaspot.multimediatechnology.at/api/. Invalid HTTP status code 404 

The error has something to do with a preflight OPTIONS request to the server - because I am sending JSON - I already tried to set the jQuery.ajax option "async" to false - didn't work either.

So far I don't have any ideas how to solve this. Would be nice if you guys could help me out.

Upvotes: 1

Views: 1888

Answers (1)

maddin2code
maddin2code

Reputation: 1354

You are facing one of this two problems.

  1. The Error tells about a 404, so in Sinatra you haven't created a route (controller) which takes the OPTIONS method for that URL, the 404 error is correct.

You can specify this route in the same way you're creating GET, POST, PUT, DELETE routes, but you can also integrate this in your before filter:

# return directly with 200 if request method is options
halt 200 if request.request_method == 'OPTIONS'

This will approve all incoming OPTIONS requests with 200 OK. There will be no 404 anymore. This is not a security issue, because you define which origin is allowed to request the API in a CORS manner.

  1. Your problem is most likely the first mentioned one, but you will face this later on as well.

In a CORS world for some HTTP actions the origin (Access-Control-Allow-Origin) can't be set to any host (*).

You can solve this problem by specifying the correct origin like so:

'Access-Control-Allow-Origin' => 'https://the.url.sending.requests.to.the.api'

Normally you want to call your API from different origins, because you have different environments (dev, test, stage, production). To archive this, you need a bit code which sets the allowed origin to the environment which is requesting. BUT WATCH OUT, don't do something which allows everything!

A possible way is having the allowed origins manually defined in your application configuration. When a CORS requests comes in, check in the before filter if the request is send from one origin you trust and set this on the fly as Access-Control-Allow-Origin.

Upvotes: 2

Related Questions