Questa risposta copre molto terreno, quindi è divisa in tre parti:
- Come utilizzare un proxy CORS per aggirare i problemi di "Nessuna intestazione Access-Control-Allow-Origin"
- Come evitare il preflight CORS
- Come risolvere i problemi "L'intestazione Access-Control-Allow-Origin non deve essere il jolly"
Come utilizzare un proxy CORS per aggirare i problemi di "Nessuna intestazione Access-Control-Allow-Origin"
Se non controlli il server a cui il tuo codice JavaScript front-end sta inviando una richiesta e il problema con la risposta da quel server è solo la mancanza dell'intestazione necessaria Access-Control-Allow-Origin
, puoi comunque far funzionare le cose, facendo la richiesta attraverso un Proxy CORS. Per mostrare come funziona, innanzitutto ecco un codice che non utilizza un 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?"))
Il motivo per cui il catch
blocco viene colpito lì è che il browser impedisce a quel codice di accedere alla risposta da cui ritorna https://example.com
. E il motivo per cui il browser lo fa è che la risposta manca Access-Control-Allow-Origin
dell'intestazione della risposta.
Ora, ecco esattamente lo stesso esempio, ma solo con un proxy CORS aggiunto in:
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?"))
Nota: se https://cors-anywhere.herokuapp.com è inattivo o non disponibile quando lo provi, vedi sotto per come distribuire il tuo server CORS Anywhere su Heroku in soli 2-3 minuti.
Il secondo frammento di codice sopra riportato può accedere correttamente alla risposta perché prendendo l'URL della richiesta e cambiandolo in https://cors-anywhere.herokuapp.com/https://example.com —solo semplicemente prefissandolo con l'URL del proxy — provoca il richiesta di esecuzione tramite tale proxy, che quindi:
- Inoltra la richiesta a
https://example.com
.
- Riceve la risposta da
https://example.com
.
- Aggiunge l'
Access-Control-Allow-Origin
intestazione alla risposta.
- Passa quella risposta, con quell'intestazione aggiunta, al codice frontend richiedente.
Il browser quindi consente al codice frontend di accedere alla risposta, poiché quella risposta con l' Access-Control-Allow-Origin
intestazione della risposta è ciò che il browser vede.
Puoi facilmente eseguire il tuo proxy usando il codice da https://github.com/Rob--W/cors-anywhere/ .
Puoi anche distribuire facilmente il tuo proxy su Heroku in letteralmente solo 2-3 minuti, con 5 comandi:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Dopo aver eseguito questi comandi, finirai con il tuo server CORS Anywhere in esecuzione su, ad esempio, https://cryptic-headland-94862.herokuapp.com/ . Quindi, invece di aggiungere il prefisso all'URL della tua richiesta https://cors-anywhere.herokuapp.com
, aggiungi come prefisso l'URL della tua istanza; ad esempio, https://cryptic-headland-94862.herokuapp.com/https://example.com .
Quindi se quando vai a provare a usare https://cors-anywhere.herokuapp.com, trovi che è inattivo (come a volte lo sarà), quindi considera di ottenere un account Heroku (se non lo hai già fatto) e prendi 2 o 3 minuti per eseguire i passaggi precedenti per distribuire il proprio server CORS Anywhere su Heroku.
Indipendentemente dal fatto che tu esegua il tuo o usi https://cors-anywhere.herokuapp.com o altri proxy aperti, questa soluzione funziona anche se la richiesta è quella che innesca i browser a fare una OPTIONS
richiesta di preflight CORS , perché in quel caso, il il proxy restituisce anche le intestazioni Access-Control-Allow-Headers
e Access-Control-Allow-Methods
necessarie per far funzionare il preflight.
Come evitare il preflight CORS
Il codice nella domanda attiva un preflight CORS, poiché invia Authorization
un'intestazione.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Anche senza quello, anche l' Content-Type: application/json
intestazione avrebbe innescato il preflight.
Che cosa significa "preflight": prima che il browser provi il POST
codice nella domanda, invierà prima una OPTIONS
richiesta al server - per determinare se il server sta optando per la ricezione di un'origine incrociata POST
che include le intestazioni Authorization
e Content-Type: application/json
.
Funziona abbastanza bene con un piccolo script di arricciatura: ottengo i miei dati.
Per testare correttamente curl
, è necessario emulare la OPTIONS
richiesta di verifica preliminare che il browser invia:
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"
... con https://the.sign_in.url
sostituito da qualunque sia il tuo sign_in
URL reale .
La risposta che il browser deve vedere da quella OPTIONS
richiesta deve includere intestazioni come questa:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Se la OPTIONS
risposta non include queste intestazioni, il browser si fermerà proprio lì e non tenterà nemmeno di inviare la POST
richiesta. Inoltre, il codice di stato HTTP per la risposta deve essere un 2xx, in genere 200 o 204. Se è un altro codice di stato, il browser si fermerà proprio lì.
Il server nella domanda sta rispondendo alla OPTIONS
richiesta con un codice di stato 501, il che apparentemente significa che sta cercando di indicare che non implementa il supporto per le OPTIONS
richieste. In genere, altri server rispondono con un codice di stato 405 "Metodo non consentito".
Quindi non sarai mai in grado di fare POST
richieste direttamente a quel server dal tuo codice JavaScript front-end se il server risponde a quella OPTIONS
richiesta con un 405 o 501 o qualcosa di diverso da un 200 o 204 o se non risponde con quelli necessari intestazioni di risposta.
Il modo per evitare di innescare un preflight per il caso nella domanda sarebbe:
- se il server non richiedeva
Authorization
un'intestazione della richiesta ma invece (ad esempio) si basava su dati di autenticazione incorporati nel corpo della POST
richiesta o come parametro di query
- se il server non ha richiesto al
POST
corpo di avere un Content-Type: application/json
tipo di supporto ma invece ha accettato il POST
corpo come application/x-www-form-urlencoded
con un parametro chiamato json
(o qualunque altra cosa) il cui valore è i dati JSON
Come risolvere i problemi "L'intestazione Access-Control-Allow-Origin non deve essere il jolly"
Ricevo un altro messaggio di errore:
Il valore dell'intestazione 'Access-Control-Allow-Origin' nella risposta non deve essere il carattere jolly '*' quando la modalità credenziali della richiesta è 'include'. L'origine ' http://127.0.0.1:3000 ' non è quindi consentito l'accesso. La modalità credenziali delle richieste avviate da XMLHttpRequest è controllata dall'attributo withCredentials.
Per una richiesta che include credenziali, i browser non consentiranno al codice JavaScript front-end di accedere alla risposta se il valore dell'intestazione della Access-Control-Allow-Origin
risposta è *
. Invece il valore in quel caso deve corrispondere esattamente l'origine del codice di frontend, http://127.0.0.1:3000
.
Vedere Richieste e caratteri jolly con credenziali nell'articolo MDS HTTP access control (CORS).
Se controlli il server a cui stai inviando la richiesta, un modo comune per gestire questo caso è configurare il server in modo che prenda il valore dell'intestazione della Origin
richiesta e rispecchi / rifletta tale valore nel valore dell'intestazione della Access-Control-Allow-Origin
risposta. Ad esempio, con nginx:
add_header Access-Control-Allow-Origin $http_origin
Ma questo è solo un esempio; altri sistemi server (web) forniscono modi simili per echo valori di origine.
Sto usando Chrome. Ho anche provato a utilizzare quel plug-in Chrome CORS
Quel plug-in Chrome CORS apparentemente sembra semplicemente Access-Control-Allow-Origin: *
inserire un'intestazione nella risposta che il browser vede. Se il plugin fosse più intelligente, quello che avrebbe fatto è impostare il valore di tale falsa Access-Control-Allow-Origin
intestazione di risposta alla vera origine del frontend codice JavaScript, http://127.0.0.1:3000
.
Quindi evita di usare quel plugin, anche per i test. È solo una distrazione. Se vuoi testare le risposte che ricevi dal server senza che il browser le filtri, è meglio usare curl -H
come sopra.
Per quanto riguarda il codice JavaScript frontend per la fetch(…)
richiesta nella domanda:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Rimuovi quelle righe. Le Access-Control-Allow-*
intestazioni sono intestazioni di risposta . Non vuoi mai inviarli in una richiesta. L'unico effetto che avrà è di innescare un browser per eseguire un preflight.