Як пропустити попередній запит на ОПЦІЇ?


93

Я розробив додаток 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.

Заздалегідь спасибі.

Відповіді:


100

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

Якщо після внесення цієї зміни ви все ще бачите попередній перегляд, тоді Angular, можливо, також додає X-заголовок до запиту.

Або у вас можуть бути заголовки (Авторизація, Керування кешем ...), які ініціюватимуть це, див .:


9
Це правильна відповідь - ваші заголовки Content-Type та Cache-Control ініціюють попередній запит. Простий GET із текстовим / звичайним типом вмісту та декількома іншими - це єдині способи ініціювати невизначений запит. Див .: developer.mozilla.org/en-US/docs/HTTP/…
Джефф Хаббард,

Ах так, забув про кеш-контроль.
Ray Nicholus,

17
Спеціальний заголовок також ініціюватиме попередню перевірку.
Себастьян Депре

2
Зміна типу вмісту для запобігання тесту OPTIONS не є відповіддю. Тип вмісту повинен збігатися з типом вмісту незалежно
ekerner

якщо це перекидання браузера, а у внутрішній системі метод Http OPTIONS заблокований, чи матиме це якийсь ефект, як-от браузер не буде викликати відповідний API для POST / PUT, оскільки OPTIONS не вдалося?
P Satish Patro

16

Як сказав Рей, ви можете зупинити це, змінивши заголовок вмісту, наприклад -

 $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(){...});

Це не надсилатиме жодного запиту на варіант перед польотом.

ПРИМІТКА: Запит не повинен мати будь-якого власного параметра заголовка. Якщо заголовок запиту містить будь-який власний заголовок, тоді браузер зробить запит перед польотом, ви не можете його уникнути.


1
Як мені це робити просто з $http?
Learnercys

Дякую, це схоже на те, що я робив. Єдині зміни - це метод GETі додатковий заголовок Authorization. Але все-таки відправляє передполіт.
Learnercys

1
Чи можете ви вставити свій запит сюди? як завивка чи щось інше? Можливо, це через заголовок авторизації, спробуйте видалити його, а потім спробуйте. Якщо ви надсилаєте користувацькі заголовки, то angular надішле передполітний запит.
vivex

pastebin.com/vRDeFiH2 Перший - це запит до $ http, а другий - дійсний запит, побудуйте його листоношею :)
Learnercys

2

При виконанні певних типів міждоменних запитів 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

2

Я думаю, найкращим способом є перевірити, чи є запит типу "ОПЦІЇ", повернути 200 із середнього посуду. У мене це спрацювало.

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

Це працює, але в OWASP рекомендується не виставляти ВАРІАНТИ. Ви погоджуєте це заблокувати у сервісі бекенда / хостингу (Nginx, Apache) тощо
P Satish Patro

0

Preflight - це функція веб-безпеки, реалізована браузером. Для Chrome ви можете вимкнути всю веб-безпеку, додавши прапор --disable-web-security.

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


Ви насправді не можете очікувати, що OP скаже своїм клієнтам вимкнути захист браузера лише для того, щоб увімкнути функцію, так ?!
сварог

@svarog це переважно для цілей розробників, в основному на виробничому сервері ви не зіткнетеся з цією проблемою.
Arijit Patra

якщо це перекидання браузера, а у внутрішній системі метод Http OPTIONS заблокований, чи матиме це якийсь ефект, як-от браузер не буде викликати відповідний API для POST / PUT, оскільки OPTIONS не вдалося?
P Satish Patro

-2

встановлення типу вмісту на undefined змусило б javascript передавати дані заголовка як є, і над написанням типових конфігурацій заголовка $ httpProvider за замовчуванням. Документація $ http

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.