1

I have an AngularJS application. It sends out requests to another server for data and so there's an OPTIONS request goes out with every $HTTP call.

When I check with fiddler there are two calls. The Options that always returns a 200 OK and then the data call.

However when I check the $HTTP it seems that it's getting the first request ( the options request ) and not getting the second request the one with real data.

Can someone point me in the right direction with this?

Here's one example of the code that is not responding correctly:

 .factory('isUsernameAvailable', function (appConstant, $q, $http) {
    return function (username) {
        var deferred = $q.defer();
        // if (!angular.isDefined(username) || username == null || username == "" || username.length < 6 ) return deferred.resolve();
        var url = appConstant.baseUrl + '/api/user/existsByName';
        $http({
            url: url,
            method: "PUT",
            data: {
                userName: username
            }
        }).then(function (data) {
                // Found the user, therefore not unique.
                deferred.reject("User name is taken");
            }, function (data) {
                // User not found, therefore unique!
                deferred.resolve();
            });
        return deferred.promise;
    }
  })

I expect it to be returning as success or failure depending on if it finds the username. But in this case it always responds as a fail/error.

Here are the requests being made:

OPTIONS http://localhost:3048/api/user/existsByName HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Access-Control-Request-Method: PUT
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://localhost:2757/Auth/register
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

giving:

HTTP/1.1 200 OK
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: http://localhost:2757
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: content-type
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcYXBpXHVzZXJcZXhpc3RzQnlOYW1l?=
X-Powered-By: ASP.NET
Date: Mon, 12 Jan 2015 17:52:12 GMT
Content-Length: 0

Then:

PUT http://localhost:3048/api/user/existsByName HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Content-Length: 35
Accept: application/json, text/plain, */*
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Authorization: null
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:2757/Auth/register
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

{"userName":"abdddcdefgg@live.com"}

giving:

HTTP/1.1 404 Not Found
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: http://localhost:2757
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Custom-Header
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcYXBpXHVzZXJcZXhpc3RzQnlOYW1l?=
X-Powered-By: ASP.NET
Date: Mon, 12 Jan 2015 17:52:12 GMT
Content-Length: 0

The problem is even if the second request returns a 200 when I debug the success and error functions it still goes to the error function all of the time.

Samantha J T Star
  • 30,952
  • 84
  • 245
  • 427
  • 1
    Is the second request succeeding in Fiddler or is there an issue with the CORS configuration? – Mike Perrenoud Jan 12 '15 at 17:35
  • The second request is succeeding. I have just tried what is suggested here: http://stackoverflow.com/questions/17756550/angularjs-cors-issues Now I just see the options request and nothing else. The option request then seems to be what the $http calls thinks is the response so that does not help at all. – Samantha J T Star Jan 12 '15 at 17:40
  • Can you post the code that is making the CORS request ? – Nicola Ferraro Jan 12 '15 at 17:41
  • Can you uplaod a screenshot with the http calls (especially headers)? – Himmet Avsar Jan 12 '15 at 17:49
  • I think the problem lies in the response code. For the OPTIONS call you need to respond with a 302 **I think** - is that what you're getting? – Mike Perrenoud Jan 12 '15 at 17:53
  • I just read the following about the response: Minimally, the response should be a 200 OK and have an Allow header with a list of HTTP methods that may be used on this resource. As an authorized user on an API, if you were to request OPTIONS /users/me, you should receive something like... 200 OK Allow: HEAD,GET,PUT,DELETE,OPTIONS – Samantha J T Star Jan 12 '15 at 18:09
  • your `Access-Control-Allow-Headers: content-type' should be changed to `Access-Control-Allow-Headers: Content-Type' because I think these are sometimes case sensitive – unobf Jan 12 '15 at 18:19

1 Answers1

1

You should use JSONP to do cross domain JSON calls. Look at the documentation here: https://docs.angularjs.org/api/ng/service/$http#jsonp. Also, your referring page and the response from the OPTIONS request must have the appropriate CORS headers set or else the browser will refuse to send the request here are the header settings that I use.

Access-Control-Allow-Headers:Content-Type, Authorization, Content-Length, X-Requested-With, Accept, x-csrf-token, origin
Access-Control-Allow-Methods:GET,PUT,POST,DELETE,OPTIONS
Access-Control-Allow-Origin:*

To call $http.jsonp with a PUT request, you would set up a configuration such as

var config = {
 method: 'POST',
 data: { test: 'test' }
};

and then pass that into the $http.jsonp call

 $http.jsonp('http://example.com', config);

Here is more documentation https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS and http://en.wikipedia.org/wiki/JSONP

unobf
  • 7,158
  • 1
  • 23
  • 36
  • Just an FYI, the most recent version of Chrome does not support wildcard on Access-Control-Allow-Origin. Better details here: https://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin-when-credentials-flag-i – ZacWolf Jan 12 '15 at 17:59
  • Which version? I have never had this problem. Also the spec explicitly allows this http://www.w3.org/TR/cors/#access-control-allow-origin-response-header#access-control-allow-origin-response-header – unobf Jan 12 '15 at 18:02
  • I am currently using: 39.0.2171.95 (64-bit) I had to write a Servlet that would pull the origin against a list of "allowed" servers, and if found include that domain specifically in the "Access-Control-Allow-Origin". The server is a Google Apps Engine java instance, would that change the formula at all? (I'm not using login). – ZacWolf Jan 12 '15 at 18:05
  • I looked but cannot see where it specifically mentions anything about CORS and JSONP. Can you explain a bit more. For example how do I do a PUT, POST, GET with JSONP? – Samantha J T Star Jan 12 '15 at 18:06
  • I am using 39.0.2171.95 (64-bit) on OS X and I just tested this and it works. Did both the cross domain and the referring servers have the CORS headers? – unobf Jan 12 '15 at 18:07
  • @SamanthaJ updated the answer to include the config object showing how to do a POST – unobf Jan 12 '15 at 18:13
  • Not exactly sure what to tell you, it may be something specific to Google Apps Engine, SSL, etc.? But the wildcard wouldn't work for me. – ZacWolf Jan 12 '15 at 18:14
  • unobf - thanks very much but if you don't mind can you point me to some documentation that explains why this might work or some web pages. With jsonp will it still send a pre flight request? – Samantha J T Star Jan 12 '15 at 18:16
  • I added some links to documentation. It will send an OPTIONS call (I think this might be cached if subsequent calls go to the same resource) – unobf Jan 12 '15 at 18:24