1

BACKGROUND

First things first, I have a Restify service running on Node which is working perfectly when I use a GUI HTTP client. I only state the previous to highlight, that this is a browser-centric issue. And if a server-side solution is needed, it is to accomodate the browser...

Here are the 100% functional HTTP requests and responses using my Restify web service and a GUI HTTP client:

Request -

POST /appointments HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: localhost:8085
Connection: close
User-Agent: Paw/2.1.1 (Macintosh; OS X/10.10.1) GCDHTTPRequest
Content-Length: 142

{
  "eventName": "Fiesta Forever",
  "time": "Fri Dec 19 2014 15:55:00 GMT-0600 (CST)",
  "phoneNumber": "13125555555"
} 

Response-

HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 1000
Content-Type: application/json
Content-Length: 37
Date: Fri, 19 Dec 2014 23:01:29 GMT
Connection: close

{"message":"Alright Alright Alright"}

And more importantly, my server creates a future cron job, which can be seen in my server's console:

Created: Fri Dec 19 2014 14:55:00 GMT-0600 (CST)



THE PROBLEM

My problem is that I am trying to write a browser interface to my service. And I am getting an error when I try making the same HTTP request using Ajax. I created the following test function which makes the HTTP request:

function testPost() {
    var jsonBody = "{\"eventName\": \"Fiesta Forever\",\"time\": \"Fri Dec 19 2014 14:15:00 GMT-0600 (CST)\",\"phoneNumber\": \"13125555555\"}";

    $.ajax({
        url: 'http://localhost:8085/appointments',
        accepts: 'application/json',
        type: 'POST',
        data: jsonBody,
        contentType: 'application/json',
        crossDomain: true,
        headers: {
         "Access-Control-Allow-Origin":true
           }
    });

}

I then load my page containing that function in my iOS emulator, and call the function from the Safari Developer console. I receive the following error:

enter image description here

EDIT: Upon removing the request headers, I receive: Failed to load resource: the server responded with a status of 406 (Not Acceptable)

SERVER-CODE

Here is the code on my server. I took the following code from the Express docs, because they were the only solution which actually seemed to add the correct headers to every response:

//CORS
server.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    res.header("Access-Control-Max-Age", "1000");
    next();
});

Can anyone help me figure out how to make a cross domain HTTP request using $.ajax which carries and receives JSON?

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Blake G
  • 581
  • 7
  • 24
  • Is the server.use above all the other http request callbacks? if not move it above it – ryanc1256 Dec 19 '14 at 23:22
  • The 405 is a bit weird. The cross-origin error is not, that stuff is difficult and has many quirks. For the 405, I would do a `console.log()` on the headers and method in the `req` object of your Node service just to be sure you know what the server is trying to handle. – Jordan Kasper Dec 19 '14 at 23:24
  • Ryan, thank you for your tip, but moving the server.use above all others did not solve the problem. Jakerella, I would love to inspect the incoming `req`s in the node service, but I can't seem to find a breakpoint which is hit. The request doesn't actually hit my `/appointments/` endpoint, so I can't put a breakpoint there or within the function handler. – Blake G Dec 19 '14 at 23:30
  • 1
    _Sending_ an `Access-Control-Allow-Origin` header with your _request_ is nonsense – that header has to be send in _response_ by the server – so remove it from your AJAX request. – CBroe Dec 19 '14 at 23:58
  • Thanks, I thought that could very well be the case. – Blake G Dec 19 '14 at 23:59
  • CBroe, making that change braught me to a 406 error, Progress!? – Blake G Dec 20 '14 at 00:01
  • 1
    406 means (by definition), that the server is not capable of serving a response of the type you requested via `Accept` header. Try removing `accepts: 'application/json'` from your AJAX settings – does that change anything? – CBroe Dec 20 '14 at 00:03
  • CBroe, you solved it. Thank you so much! – Blake G Dec 20 '14 at 00:05
  • OK, I’ll sum that up as an answer. – CBroe Dec 20 '14 at 00:08

1 Answers1

1

First of all, Access-Control-Allow-Origin is a response header that has to be send by the server – sending it as a request header with the client request does not only not make sense, but seems to be what makes the server refuse your request here – because with Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept it told you what request headers it will accept, and Access-Control-Allow-Origin is not among those.

After that you got a 406 Not Acceptable, meaning the server did not see itself able to respond with data of a content type that was requested via the Accept header. So removing accepts: 'application/json' does make jQuery not tell the server any more that you expect a specific content type, but just “give me whatever you got” – which in this case seems to satisfy the server …

… and make it respond with Content-Type: application/json anyway, which is kinda weird, because that should be exactly what jQuery was asking for (and your first request via GUI showed as well). I don’t know if jQuery makes something else out of that setting (you could try and see if your browser’s developer tools network panel shows anything wrong with the request headers) … but problem solved, and that’s what counts, right? :-)

CBroe
  • 91,630
  • 14
  • 92
  • 150