CORS - Jak przeprowadzić „inspekcję wstępną” httprequest?

94

Próbuję wysłać żądanie HTTP między domenami do usługi WCF (której jestem właścicielem). Przeczytałem kilka technik pracy z ograniczeniami skryptów międzydomenowych. Ponieważ moja usługa musi obsługiwać zarówno żądania GET, jak i POST, nie mogę zaimplementować jakiegoś dynamicznego tagu skryptu, którego src jest adresem URL żądania GET. Ponieważ mogę wprowadzać zmiany na serwerze, zacząłem próbować zastosować obejście polegające na skonfigurowaniu odpowiedzi serwera tak, aby zawierały nagłówek „Access-Control-Allow-Origin” i żądania „preflight” z żądaniem i OPTIONS. Pomysł zaczerpnąłem z tego postu: Jak działa CORS

Po stronie serwera moją metodą internetową jest dodanie „Access-Control-Allow-Origin: *” do odpowiedzi HTTP. Widzę, że odpowiedzi zawierają teraz ten nagłówek. Moje pytanie brzmi: Jak mogę „sprawdzić” wniosek (OPCJE)? Używam jQuery.getJSON, aby wykonać żądanie GET, ale przeglądarka anuluje żądanie od razu z niesławnym:

Origin http: // localhost nie jest dozwolony przez Access-Control-Allow-Origin

Czy ktoś zna tę technikę CORS? Jakie zmiany należy wprowadzić po stronie klienta, aby wstępnie przesłać moje żądanie?

Dzięki!

Nacięcie
źródło

Odpowiedzi:

159

Podczas żądania inspekcji wstępnej powinny zostać wyświetlone następujące dwa nagłówki: Access-Control-Request-Method i Access-Control-Request-Headers. Te nagłówki żądań proszą serwer o pozwolenie na wykonanie rzeczywistego żądania. Twoja odpowiedź wstępna musi potwierdzić te nagłówki, aby rzeczywiste żądanie zadziałało.

Na przykład załóżmy, że przeglądarka wysyła żądanie z następującymi nagłówkami:

Origin: http://yourdomain.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header

Twój serwer powinien wtedy odpowiedzieć następującymi nagłówkami:

Access-Control-Allow-Origin: http://yourdomain.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-Custom-Header

Zwróć szczególną uwagę na nagłówek odpowiedzi Access-Control-Allow-Headers. Wartość tego nagłówka powinna być tymi samymi nagłówkami w nagłówku żądania Access-Control-Request-Headers i nie może mieć wartości „*”.

Po wysłaniu tej odpowiedzi na żądanie inspekcji wstępnej przeglądarka wykona właściwe żądanie. Możesz dowiedzieć się więcej o CORS tutaj: http://www.html5rocks.com/en/tutorials/cors/

monsur
źródło
czy możesz dodać wiele domen do Access-Control-Allow-Origin?
botbot
@botbot Prawdopodobnie już to rozwiązałeś, ale na wypadek, gdyby inni się zastanawiali, mogą to zrobićAccess-Control-Allow-Origin: *
Steve Chambers
2
Prawdopodobnie coś przeoczyłem. Czy powinienem więc wysłać dwa żądania XMLHttp? Jeden do inspekcji wstępnej; sprawdzić odpowiedź w przypadku sukcesu, a następnie wysłać właściwe zapytanie?
Kangkan
15
@Kangkan, nie musisz się martwić o wysłanie zapytania wstępnego. Jeśli żądanie wymaga inspekcji wstępnej, przeglądarka wyśle ​​je za Ciebie.
monsur
4
DZIĘKUJĘ za fragment `` zwracaj szczególną uwagę '' ... który rozwiązał mój problem z node / expressjs. Udało mi się dodać filtr przechwytujący te żądania wstępne//cors and preflight filtering app.all('*', function(req, res, next){.. //preflight needs to return exact request-header res.set('Access-Control-Allow-Headers', req.headers['access-control-request-headers']); if ('OPTIONS' == req.method) return res.send(204);next(); });
Kurtfm
0

Chociaż ten wątek sięga 2014 roku, dla wielu z nas problem nadal może być aktualny. Oto jak sobie z tym poradziłem w kontekście jQuery 1.12 / PHP 5.6:

  • jQuery wysłał żądanie XHR, używając tylko ograniczonych nagłówków; wysłano tylko „Origin”.
  • Żądanie inspekcji wstępnej nie było potrzebne.
  • Serwer musiał tylko wykryć takie żądanie i dodać „Access-Control-Allow-Origin:”. Nagłówek $ _SERVER ['HTTP_ORIGIN'] po wykryciu, że był to XHR z innych źródeł.

Przykład kodu PHP:

if (!empty($_SERVER['HTTP_ORIGIN'])) {
    // Uh oh, this XHR comes from outer space...
    // Use this opportunity to filter out referers that shouldn't be allowed to see this request
    if (!preg_match('@\.partner\.domain\.net$@'))
        die("End of the road if you're not my business partner.");

    // otherwise oblige
    header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
}
else {
    // local request, no need to send a specific header for CORS
}

W szczególności nie należy dodawać, exit;ponieważ inspekcja wstępna nie jest potrzebna.

Fabien Haddadi
źródło