How to make a preemptive REST call with ajax?

advertisements

I'm asking for some help and explanation as I'm just confused.

I have a jQuery function that, with ajax, is doing a POST call to some server.

var login = $("#email1").val();
var password = $("#password1").val();
var summary = $("#summary").val();
var details = $("#details").val();
var address = $("#address").val();
var str = login + ':' + password;
var credentials = utf8_to_b64(str);
function utf8_to_b64( str ) {
       return window.btoa(unescape(encodeURIComponent( str )));
       }
$.ajax({
        beforeSend: function (xhr) {
                   xhr.setRequestHeader("Authorization", "Basic " + credentials);
                   },
        crossDomain: true,
        //fails with or without next two arguments
        username: login,
        password:password,
        url: "https://blablablasomethingrelevant",
        type: "POST",
        dataType: "json",
        contentType: "application/json",
        data: JSON.stringify({"fields":{properdatahere}}),
        async: false,
        success: function (data) {
                         alert(data);
                      },
        error: function (xhr, ajaxOptions, thrownError) {
             alert(xhr.status);
             alert(thrownError);
             alert(xhr.responseText);
             alert(xhr);
             },

             });

The error I get is "No 'Access-Control-Allow-Origin' header is present on the requested resource". Of course I googled for it and answer is always that it is "self explaining" blabla error, and the fault in on the server side and I need to do some tricks over there. These answers would make sense if I would fail to perform the same POST call with all other technologies.

When I did exactly the same with java, using jersey client it worked fine, the same using rest client from wiztools.org (had to tick option preemptive)

Client client = Client.create();
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(login, password));
WebResource webResource = client.resource("https://blablablasomethingrelevant");
String input = "{"fields":{properdatahere}";
ClientResponse response = webResource.type("application/json").post(ClientResponse.class, input);

So can anybody tell me why it works with java and jersey and not with jquery and ajax? How to make it finally work with ajax?


The reason it works with Java is that Java is not run in the client's browser. For security reasons, browsers will not allow Javascript AJAX requests to domains other than the domain the page was loaded from. For example, if you load a page from http://www.example.com/, the javascript from that page will not be able to do AJAX requests to http://api.othersite.com/ or even http://api.example.com/.

There are some workarounds. One is JSONP (http://en.wikipedia.org/wiki/JSONP) and another is to set the CORS headers (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). Both requires changes to the API you are calling, so you can't solve it on your side only.

What you could do is add a resource on your server, such as http://www.example.com/api/resource which then, in your backend (Java in your case?), makes a request to http://api.othersite.com/ using code similar to what you wrote in the question. Your Javascript could then call http://www.example.com/api/resource without problems. In short, you are proxying the requests through your backend to the third-party API.