AngularJS: POST Data для внешнего REST API

У меня есть базовая настройка службы AngularJS, например:

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'
        }
    }
});
});

и я использую его следующим образом:

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);
});

Проблема одна: User.update(), несмотря на то, что метод установлен на POST, продолжает отправлять OPTIONS в качестве метода запроса.

Хотя инструменты Chrome Dev сообщают о заголовке запроса Access-Control-Request-Method: отправляется POST (не уверен, что это что-то значит).

Проблема вторая: Я продолжаю получать ошибку с CORS, несмотря на то, что эти заголовки установлены в коде API:

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

Эта проблема появляется только при выполнении запроса, отличного от GET.

Какой правильный способ справиться с этим? Я также заглянул в JSONP, но при этом это RESTful api, я не уверен, как обойти проблемы только с поддержкой GET.

Ответы

Ответ 1

Ваши две проблемы на самом деле являются одной проблемой. Запрос OPTIONS является частью процесса CORS. Для запросов POST браузер сначала отправляет вызов OPTIONS, и сервер отвечает, если это нормально для его выполнения.

Если запрос OPTIONS завершился с ошибкой, Angular/Chrome показывает причину в консоли. Например:

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. 

Вероятно, вам также необходимо установить заголовки Access-Control-Allow на сервере:

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

x-xrsf-token для angular 'для предотвращения CSRF. Возможно, вам придется добавить больше заголовков, в зависимости от того, что вы отправляете от клиента.

Вот очень хорошее руководство по CORS: https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS

Ответ 2

В AngularJS для работы CORS вам также придется перезаписать настройки по умолчанию 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'];
    }
]);

Просто установка useXDomain в true недостаточно. Запрос AJAX также отправьте с заголовком X-Requested-With, который указывает, что они являются AJAX. Удаление заголовка необходимо, поэтому сервер не отклоняет входящий запрос.

Примечание. Ответ работает только для более ранней версии AngularJS, предшествующей 1.2. С 1,2 и выше вам не нужно ничего делать, чтобы включить CORS.

Ответ 3

Лучше решить эту проблему на сервере. На apache вы можете решить это как в файле .htaccess. Это источник боли для разработки angular и может быть решен в angular, но, вероятно, это не лучший способ сделать это.

Header set Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"