Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: POST Data to External REST API

I have a basic AngularJS service setup like so:

app.factory('User', function($resource) {
return $resource('http://api.mysite.com/user/:action:id/:attr', {}, {
    history: {
        method: 'GET',
        params: {
            attr: 'history'
        }
    },
    update: {
        method: 'POST',
        params: {
            name: 'test'
        }
    }
});
});

and I use it like this:

User.history({id: 'testID'}, function(data) {
    console.log('got history');
    console.log(data);
});
User.update({id: 'me'}, function(data) {
    console.log('updated');
    console.log(data);
});

Problem one: User.update(), despite having the method set to POST, keeps sending OPTIONS as the request method.

Though Chrome Dev tools reports the request header Access-Control-Request-Method:POST is sent as well (Not sure if that means anything).

Problem two: I keep getting an error with CORS, despite having these headers set in the API code:

header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS");

This problem only shows up though if making a non-GET request.

What's the proper way to be handling this? I've also looked into JSONP, but with this being a RESTful api, I'm not sure how to get around the problems with only GET support.

like image 936
Lucas Raines Avatar asked Jun 25 '13 04:06

Lucas Raines


2 Answers

Your two problems are actually one problem. The OPTIONS request is part of the CORS process. For POST requests, the browser first sends an OPTIONS call, and the server responds if it is okay to execute it.

If the OPTIONS request fails, Angular / Chrome shows you the reason in the console. For example:

OPTIONS https://*** Request header field Content-Type is not allowed by Access-Control-Allow-Headers. angular.min.js:106

XMLHttpRequest cannot load https://***. Request header field Content-Type is not allowed by Access-Control-Allow-Headers. 

You probably have to set Access-Control-Allow Headers on the server, too:

header('Access-Control-Allow-Headers: Content-Type, x-xsrf-token')

x-xrsf-token is for angular' to prevent CSRF. You may have to add more headers, depending on what you send from the client.

Here is a very good guide on CORS: https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS

like image 156
Narretz Avatar answered Oct 02 '22 14:10

Narretz


In AngularJS to make CORS working you also have to overwrite default settings of the angular httpProvider:

var myApp = angular.module('myApp', [
    'myAppApiService']);

myApp.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }
]);

Just setting useXDomain to true is not enough. AJAX request are also send with the X-Requested-With header, which indicate them as being AJAX. Removing the header is necessary, so the server is not rejecting the incoming request.

Note: Answer only works for older AngularJS version previous to 1.2. With 1.2 and above you don't have to do do anything to enable CORS.

like image 42
Torsten Engelbrecht Avatar answered Oct 02 '22 14:10

Torsten Engelbrecht