Jak pominąć żądanie wstępne OPCJE?

93

Opracowałem aplikację PhoneGap, która jest obecnie przekształcana w witrynę mobilną. Wszystko działa sprawnie poza jedną małą usterką. Używam interfejsu API innej firmy za pośrednictwem żądania POST, które działa dobrze w aplikacji, ale nie działa w wersji mobilnej strony internetowej.

Po bliższym przyjrzeniu się wydaje się, że AngularJS (wydaje mi się, że faktycznie przeglądarka) najpierw wysyła żądanie OPTIONS. Dowiedziałem się dzisiaj wiele o CORS, ale nie wiem, jak go całkowicie wyłączyć. Nie mam dostępu do tego API (więc zmiany po tej stronie są niemożliwe), ale dodali domenę, nad którą pracuję, do nagłówka Access-Control-Allow-Origin.

Oto kod, o którym mówię:

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

Jak mogę uniemożliwić przeglądarce (lub AngularJS) wysyłanie żądania OPCJI i po prostu przejść do rzeczywistego żądania POST? Używam AngularJS 1.2.0.

Z góry dziękuję.

Bram Vandewalle
źródło

Odpowiedzi:

100

Inspekcja wstępna jest uruchamiana przez typ zawartości application/json. Najprostszym sposobem, aby temu zapobiec, jest ustawienie typu zawartości text/plainw Twoim przypadku. application/x-www-form-urlencoded& multipart/form-dataTypy treści są również dopuszczalne, ale oczywiście będziesz musiał odpowiednio sformatować ładunek żądania.

Jeśli po wprowadzeniu tej zmiany nadal widzisz inspekcję wstępną, to Angular może również dodawać nagłówek X do żądania.

Lub możesz mieć nagłówki (autoryzacja, kontrola pamięci podręcznej ...), które je wyzwolą, zobacz:

Ray Nicholus
źródło
9
To jest poprawna odpowiedź - nagłówki Content-Type i Cache-Control wyzwalają żądanie inspekcji wstępnej. Zwykły GET z typem zawartości tekst / zwykły i kilka innych to jedyne sposoby wyzwalania niepreflektorowanego żądania. Zobacz: developer.mozilla.org/en-US/docs/HTTP/ ...
Jeff Hubbard
Ach tak, zapomniałem o Cache-Control.
Ray Nicholus,
17
Niestandardowy nagłówek również wyzwoli inspekcję wstępną.
Sébastien Deprez
2
Zmiana typu zawartości w celu zapobieżenia testowi OPCJI nie jest odpowiedzią. Typ treści powinien pasować do typu treści niezależnie od tego
ekerner
jeśli wyrzuca przeglądarkę i w zapleczu metoda Http OPTIONS jest zablokowana, czy będzie to miało jakikolwiek skutek, taki jak przeglądarka nie będzie wywoływać odpowiedniego interfejsu API dla POST / PUT, ponieważ OPCJE nie powiodły się?
P Satish Patro
16

Jak powiedział Ray, możesz to zatrzymać, modyfikując nagłówek treści, taki jak -

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

Na przykład -

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

Lub bezpośrednio na telefon -

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

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

Nie spowoduje to wysłania żadnej prośby o opcję przed lotem.

UWAGA: Żądanie nie powinno mieć żadnego niestandardowego parametru nagłówka, jeśli nagłówek żądania zawiera dowolny niestandardowy nagłówek, przeglądarka wykona żądanie przed wysłaniem, nie możesz tego uniknąć.

vivex
źródło
1
Jak mam to zrobić tylko z $http?
learnercys
Dzięki, to podobne do tego, co robiłem. Jedyne zmiany to metoda GETi dodatkowy nagłówek Authorization. Ale nadal wysyłam wstępną inspekcję.
learnercys
1
Czy możesz wkleić tutaj swoją prośbę? jak lok czy coś? Może to z powodu nagłówka Authorization, spróbuj go usunąć, a następnie spróbuj. Jeśli wysyłasz niestandardowe nagłówki, angular wyśle ​​żądanie przed lotem.
vivex
pastebin.com/vRDeFiH2 Pierwsze to żądanie do $ http, a drugie to prawidłowe żądanie, zbuduj je przez listonosza :)
learnercys
2

Podczas wykonywania pewnych typów żądań AJAX międzydomenowych, nowoczesne przeglądarki obsługujące CORS wstawiają dodatkowe żądanie „inspekcji wstępnej” w celu określenia, czy mają uprawnienia do wykonania tej czynności. Z przykładowego zapytania:

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

W wyniku tego fragmentu widzimy, że na adres wysłano dwa zapytania (OPCJE i GET). Odpowiedź z serwera zawiera nagłówki potwierdzające dopuszczalność zapytania GET. Jeśli serwer nie jest skonfigurowany do prawidłowego przetwarzania żądania OPTIONS, żądania klientów nie powiodą się. Na przykład:

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
M. Void
źródło
2

Myślę, że najlepszym sposobem jest sprawdzenie, czy żądanie jest typu „OPCJE”, zwróć 200 z produktów pośrednich. U mnie to zadziałało.

express.use('*',(req,res,next) =>{
      if (req.method == "OPTIONS") {
        res.status(200);
        res.send();
      }else{
        next();
      }
    });
Devbrat Raghuvanshi
źródło
Działa, ale w OWASP nie zaleca się ujawniania OPCJI. Blokujesz pogodę w usłudze backend / hostowanej (Nginx, Apache) itp.
P Satish Patro
0

Inspekcja wstępna to funkcja zabezpieczeń internetowych wdrażana przez przeglądarkę. W przeglądarce Chrome możesz wyłączyć wszystkie zabezpieczenia internetowe, dodając flagę --disable-web-security.

Na przykład: „C: \ Program Files \ Google \ Chrome \ Application \ chrome.exe” --disable-web-security --user-data-dir = „C: \ newChromeSettingsWithoutSecurity”. Możesz najpierw utworzyć nowy skrót do chrome, przejść do jego właściwości i zmienić cel jak wyżej. To powinno pomóc!

Arijit Patra
źródło
Nie możesz oczekiwać, że OP powie swoim klientom, aby wyłączyli zabezpieczenia przeglądarki tylko po to, aby włączyć funkcję, prawda ?!
svarog
@svarog jest to głównie dla celów deweloperskich, głównie na serwerze produkcyjnym, nie napotkasz tego problemu.
Arijit Patra
jeśli wyrzuca przeglądarkę i w zapleczu metoda Http OPTIONS jest zablokowana, czy będzie to miało jakikolwiek skutek, taki jak przeglądarka nie będzie wywoływać odpowiedniego interfejsu API dla POST / PUT, ponieważ OPCJE nie powiodły się?
P Satish Patro
-2

ustawienie typu zawartości na undefined spowodowałoby, że javascript przekazałoby dane nagłówka w takiej postaci, w jakiej jest, i nadpisanie domyślnych konfiguracji kątowych nagłówków $ httpProvider. Dokumentacja Angular $ http

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
Theophilus Omoregbee
źródło