Ta odpowiedź obejmuje wiele gruntów, dlatego jest podzielona na trzy części:
- Jak korzystać z serwera proxy CORS, aby obejść problemy „Brak nagłówka kontroli dostępu - zezwól na pochodzenie”
- Jak uniknąć inspekcji wstępnej CORS
- Jak naprawić problem „Nagłówek Access-Control-Allow-Origin nie może być znakiem wieloznacznym”
Jak korzystać z serwera proxy CORS, aby obejść problemy „Brak nagłówka kontroli dostępu - zezwól na pochodzenie”
Jeśli nie kontrolujesz serwera, twój kod JavaScript frontonu wysyła żądanie, a problemem z odpowiedzią z tego serwera jest po prostu brak niezbędnego Access-Control-Allow-Origin
nagłówka, możesz nadal działać - wysyłając żądanie za pomocą Serwer proxy CORS. Aby pokazać, jak to działa, najpierw oto kod, który nie używa proxy CORS:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Powodem jest catch
blokowanie przeglądarki, ponieważ przeglądarka uniemożliwia temu kodowi dostęp do odpowiedzi, z której pochodzi https://example.com
. Powodem tego jest brak Access-Control-Allow-Origin
odpowiedzi w nagłówku odpowiedzi.
Oto dokładnie ten sam przykład, ale z dodanym serwerem proxy CORS:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Uwaga: Jeśli https://cors-anywhere.herokuapp.com nie działa lub jest niedostępny podczas próby, zapoznaj się z poniższymi instrukcjami wdrażania własnego serwera CORS Anywhere w Heroku w zaledwie 2-3 minuty.
Drugi fragment kodu powyżej może uzyskać dostęp do odpowiedzi, ponieważ pobranie adresu URL żądania i zmiana go na https://cors-anywhere.herokuapp.com/https://example.com - po prostu poprzedzając go adresem URL proxy - powoduje żądanie wykonania za pośrednictwem tego serwera proxy, który następnie:
- Przekazuje żądanie do
https://example.com
.
- Otrzymuje odpowiedź od
https://example.com
.
- Dodaje
Access-Control-Allow-Origin
nagłówek do odpowiedzi.
- Przekazuje tę odpowiedź z tym dodanym nagłówkiem z powrotem do żądającego kodu interfejsu użytkownika.
Przeglądarka zezwala następnie kodowi frontonu na dostęp do odpowiedzi, ponieważ ta odpowiedź z Access-Control-Allow-Origin
nagłówkiem odpowiedzi jest tym, co przeglądarka widzi.
Możesz łatwo uruchomić własny serwer proxy za pomocą kodu z https://github.com/Rob--W/cors-anywhere/ .
Możesz również łatwo wdrożyć własne proxy w Heroku w dosłownie zaledwie 2-3 minuty, za pomocą 5 poleceń:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Po uruchomieniu tych poleceń uzyskasz własny serwer CORS Anywhere działający np . Https://cryptic-headland-94862.herokuapp.com/ . Zamiast więc poprzedzać URL żądania https://cors-anywhere.herokuapp.com
, należy go poprzedzić adresem URL własnego wystąpienia; np . https://cryptic-headland-94862.herokuapp.com/https://example.com .
Jeśli więc spróbujesz użyć https://cors-anywhere.herokuapp.com, okaże się, że nie działa (co czasami będzie), to rozważ założenie konta Heroku (jeśli jeszcze tego nie zrobiłeś) i weź 2 lub 3 minuty na wykonanie powyższych kroków, aby wdrożyć własny serwer CORS Anywhere na Heroku.
Niezależnie od tego, czy prowadzisz własny, czy używasz https://cors-anywhere.herokuapp.com lub innego otwartego serwera proxy, to rozwiązanie działa nawet wtedy, gdy jest to żądanie, które uruchamia przeglądarki w celu wykonania OPTIONS
żądania inspekcji wstępnej CORS - ponieważ w takim przypadku proxy również odsyła nagłówki Access-Control-Allow-Headers
i Access-Control-Allow-Methods
nagłówki potrzebne do pomyślnego przebiegu inspekcji wstępnej.
Jak uniknąć inspekcji wstępnej CORS
Kod w pytaniu uruchamia inspekcję wstępną CORS, ponieważ wysyła Authorization
nagłówek.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Nawet bez tego Content-Type: application/json
nagłówek uruchomiłby również inspekcję wstępną.
Co oznacza „inspekcja wstępna”: zanim przeglądarka wypróbuje POST
kod w pytaniu, najpierw wyśle OPTIONS
żądanie do serwera - w celu ustalenia, czy serwer zgadza się na otrzymanie źródła krzyżowego POST
zawierającego nagłówki Authorization
i Content-Type: application/json
.
Działa całkiem nieźle z małym skryptem curl - otrzymuję moje dane.
Aby poprawnie przetestować curl
, musisz emulować OPTIONS
żądanie inspekcji wstępnej wysyłane przez przeglądarkę:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
… Z https://the.sign_in.url
zastąpionym przez rzeczywisty sign_in
adres URL.
Odpowiedź, którą przeglądarka musi zobaczyć z tego OPTIONS
żądania, musi zawierać takie nagłówki:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Jeśli OPTIONS
odpowiedź nie zawiera tych nagłówków, przeglądarka zatrzyma się w tym miejscu i nigdy nawet nie spróbuje wysłać POST
żądania. Ponadto kod stanu HTTP dla odpowiedzi musi wynosić 2xx - zwykle 200 lub 204. Jeśli jest to inny kod stanu, przeglądarka zatrzyma się w tym miejscu.
Serwer w pytaniu odpowiada na OPTIONS
żądanie kodem stanu 501, co najwyraźniej oznacza, że próbuje wskazać, że nie implementuje obsługi OPTIONS
żądań. Inne serwery zwykle odpowiadają kodem stanu 405 „Metoda niedozwolona” w tym przypadku.
Więc nigdy nie będziesz w stanie wysyłać POST
żądań bezpośrednio do tego serwera z kodu JavaScript frontonu, jeśli serwer odpowie na to OPTIONS
żądanie 405 lub 501 lub czymkolwiek innym niż 200 lub 204 lub jeśli nie odpowie na te niezbędne nagłówki odpowiedzi.
Sposobem uniknięcia uruchomienia inspekcji wstępnej dla sprawy w pytaniu byłoby:
- jeśli serwer nie wymagał
Authorization
nagłówka żądania, ale zamiast tego (na przykład) polegał na danych uwierzytelniających osadzonych w treści POST
żądania lub jako parametr zapytania
- jeśli serwer nie wymagał, aby
POST
treść miała Content-Type: application/json
typ nośnika, ale zamiast tego zaakceptował POST
treść jak application/x-www-form-urlencoded
w przypadku parametru o nazwie json
(lub cokolwiek innego), którego wartością są dane JSON
Jak naprawić problem „Nagłówek Access-Control-Allow-Origin nie może być znakiem wieloznacznym”
Otrzymuję kolejny komunikat o błędzie:
Wartością nagłówka „Access-Control-Allow-Origin” w odpowiedzi nie może być symbol wieloznaczny „*”, gdy tryb poświadczeń żądania to „include”. W związku z tym źródło „ http://127.0.0.1:3000 ” nie ma dostępu. Tryb poświadczeń żądań inicjowanych przez XMLHttpRequest jest kontrolowany przez atrybut withCredentials.
W przypadku żądania zawierającego poświadczenia przeglądarki nie pozwalają kodowi JavaScript frontonu uzyskać dostęp do odpowiedzi, jeśli wartość Access-Control-Allow-Origin
nagłówka odpowiedzi wynosi *
. Zamiast wartość w tym przypadku należy dokładnie dopasować pochodzenie kodzie frontend, w http://127.0.0.1:3000
.
Zobacz Poświadczone żądania i symbole wieloznaczne w artykule MDN kontroli dostępu HTTP (CORS).
Jeśli kontrolujesz serwer, na który wysyłasz żądanie, to typowym sposobem radzenia sobie z tą sprawą jest skonfigurowanie serwera tak, aby pobierał wartość Origin
nagłówka żądania i wysyłał echo / odbicie z powrotem do wartości Access-Control-Allow-Origin
nagłówka odpowiedzi. Na przykład z nginx:
add_header Access-Control-Allow-Origin $http_origin
Ale to tylko jeden przykład; inne (serwerowe) systemy serwerowe zapewniają podobne sposoby echa wartości początkowych.
Używam Chrome. Próbowałem też użyć tej wtyczki Chrome CORS
Ta wtyczka Chrome CORS najwyraźniej po prostu wstrzykuje Access-Control-Allow-Origin: *
nagłówek do odpowiedzi, którą widzi przeglądarka. Jeśli wtyczka byli mądrzejsi, co to się robi jest ustawienie wartości tego fałszywy Access-Control-Allow-Origin
nagłówku odpowiedzi do rzeczywistego pochodzenia swojej frontend kod JavaScript http://127.0.0.1:3000
.
Unikaj więc używania tej wtyczki, nawet do testowania. To tylko odwrócenie uwagi. Jeśli chcesz sprawdzić, jakie odpowiedzi otrzymujesz z serwera bez filtrowania ich przez przeglądarkę, lepiej użyć curl -H
powyższej metody .
Jeśli chodzi o kod JavaScript frontonu dla fetch(…)
żądania w pytaniu:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Usuń te linie. Te Access-Control-Allow-*
nagłówki są odpowiedzi nagłówki. Nigdy nie chcesz wysyłać ich w żądaniu. Jedyny efekt, jaki będzie miał, to uruchomienie przeglądarki w celu przeprowadzenia inspekcji wstępnej.