Как пропустить предварительный запрос OPTIONS в AngularJS

Я разработал приложение PhoneGap, которое сейчас трансформируется в мобильный веб-сайт. Все работает плавно, кроме одного небольшого глюка. Я использую определенный сторонний API через POST-запрос, который отлично работает в приложении, но не работает в версии для мобильного веб-сайта.

При ближайшем рассмотрении кажется, что AngularJS (я полагаю, браузер на самом деле) сначала отправляет запрос OPTIONS. Сегодня я многое узнал о CORS, но не могу понять, как вообще отключить его. У меня нет доступа к этому API (поэтому изменения на этой стороне невозможны), но они добавили домен, над которым я работаю, в свой заголовок Access-Control-Allow-Origin.

Это код, о котором я говорю:

        var request = {
                language: 'fr',
                barcodes: [
                    {
                        barcode: 'somebarcode',
                        description: 'Description goes here'
                    }
                ]
            };
        }
        var config = {
            headers: { 
                'Cache-Control': 'no-cache',
                'Content-Type': 'application/json'
            }
        };
        $http.post('http://somedomain.be/trackinginfo', request, config).success(function(data, status) {
            callback(undefined, data);
        }).error(function(data, status) {
            var err = new Error('Error message');
            err.status = status;
            callback(err);
        });

Как я могу запретить браузеру (или AngularJS) отправлять этот запрос OPTIONS и просто перейти к фактическому запросу POST? Я использую AngularJS 1.2.0.

Заранее спасибо.

5 ответов

Решение

Предпечатная проверка запускается вашим типом контента application/json, Самый простой способ предотвратить это - установить Content-Type как text/plain в твоем случае. application/x-www-form-urlencoded & multipart/form-data Типы контента также приемлемы, но вам, конечно, нужно соответствующим образом отформатировать полезную нагрузку.

Если после внесения этого изменения вы все еще видите предполёт, то Angular также может добавить X-заголовок к запросу.

Или у вас могут быть заголовки (Authorization, Cache-Control...), которые будут его запускать, смотрите:

Как сказал Рэй, вы можете остановить это, изменив заголовок содержимого, например:

 $http.defaults.headers.post["Content-Type"] = "text/plain";

Например -

angular.module('myApp').factory('User', ['$resource','$http',
    function($resource,$http){
        $http.defaults.headers.post["Content-Type"] = "text/plain";
        return $resource(API_ENGINE_URL+'user/:userId', {}, {
            query: {method:'GET', params:{userId:'users'}, isArray:true},
            getLoggedIn:{method:'GET'}
        });
    }]);

Или прямо на звонок -

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': 'text/plain'
 },
 data: { test: 'test' }
}

$http(req).then(function(){...}, function(){...});

Это не отправит запрос на предполетную опцию.

ПРИМЕЧАНИЕ. В запросе не должно быть никакого пользовательского параметра заголовка. Если заголовок запроса содержит какой-либо пользовательский заголовок, то браузер сделает предполетный запрос, вы не можете его избежать.

При выполнении определенных типов междоменных запросов AJAX современные браузеры, поддерживающие CORS, будут вставлять дополнительный предварительный запрос, чтобы определить, есть ли у них разрешение на выполнение действия. Из примера запроса:

$http.get( ‘https://example.com/api/v1/users/’ +userId,
  {params:{
           apiKey:’34d1e55e4b02e56a67b0b66’
          }
  } 
);

В результате этого фрагмента мы видим, что на адрес было отправлено два запроса (OPTIONS и GET). Ответ от сервера включает заголовки, подтверждающие допустимость запроса GET. Если ваш сервер не настроен для правильной обработки запроса OPTIONS, клиентские запросы не будут выполнены. Например:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept, origin, x-requested-with, content-type
Access-Control-Allow-Methods: DELETE
Access-Control-Allow-Methods: OPTIONS
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Methods: GET
Access-Control-Allow-Methods: POST
Access-Control-Allow-Orgin: *
Access-Control-Max-Age: 172800
Allow: PUT
Allow: OPTIONS
Allow: POST
Allow: DELETE
Allow: GET

Я думаю, что лучший способ - это проверить, возвращает ли запрос типа "OPTIONS" 200 из промежуточного программного обеспечения. Это сработало для меня.

express.use('*',(req,res,next) =>{
      if (req.method == "OPTIONS") {
        res.status(200);
        res.send();
      }else{
        next();
      }
    });

Предварительная проверка - это функция веб-безопасности, реализованная браузером. Для Chrome вы можете отключить всю веб-безопасность, добавив флаг --disable-web-security.

Например: "C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\newChromeSettingsWithoutSecurity" . Сначала вы можете создать новый ярлык хрома, перейти к его свойствам и изменить цель, как указано выше. Это должно помочь!

Установка типа содержимого в неопределенное значение заставит javascript передавать данные заголовка как есть, и перезаписывать стандартные угловые конфигурации заголовка $httpProvider по умолчанию. Angular $ http Документация

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
Другие вопросы по тегам