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-Originnagłó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 catchblokowanie 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-Originodpowiedzi 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-Originnagłó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-Originnagłó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-Headersi Access-Control-Allow-Methodsnagłó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 Authorizationnagłówek.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Nawet bez tego Content-Type: application/jsonnagłówek uruchomiłby również inspekcję wstępną.
Co oznacza „inspekcja wstępna”: zanim przeglądarka wypróbuje POSTkod w pytaniu, najpierw wyśle OPTIONSżądanie do serwera - w celu ustalenia, czy serwer zgadza się na otrzymanie źródła krzyżowego POSTzawierającego nagłówki Authorizationi 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.urlzastąpionym przez rzeczywisty sign_inadres 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 OPTIONSodpowiedź 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ł
Authorizationnagłó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
POSTtreść miała Content-Type: application/jsontyp nośnika, ale zamiast tego zaakceptował POSTtreść jak application/x-www-form-urlencodedw 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-Originnagłó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ść Originnagłówka żądania i wysyłał echo / odbicie z powrotem do wartości Access-Control-Allow-Originnagłó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-Originnagłó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 -Hpowyż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.