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ę.

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:


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ąć.


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

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

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!


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);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.