Esta respuesta cubre mucho terreno, por lo que se divide en tres partes:
- Cómo usar un proxy CORS para solucionar los problemas de "Sin encabezado Access-Control-Allow-Origin"
- Cómo evitar la verificación previa de CORS
- Cómo corregir “encabezado Access-Control-Allow-Origen no debe ser el comodín” problemas
Cómo usar un proxy CORS para solucionar los problemas de "Sin encabezado Access-Control-Allow-Origin"
Si no controla el servidor, su código JavaScript frontend está enviando una solicitud, y el problema con la respuesta de ese servidor es simplemente la falta de la necesaria Access-Control-Allow-Origin
encabezado , aún puede hacer que las cosas funcionen, haciendo la solicitud a través de un CORS proxy. Para mostrar cómo funciona, primero hay un código que no usa 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?"))
La razón por la que el catch
bloque se ve afectado es que el navegador evita que ese código acceda a la respuesta que regresa https://example.com
. Y la razón por la que el navegador hace eso es que la respuesta carece del Access-Control-Allow-Origin
encabezado de respuesta.
Ahora, este es exactamente el mismo ejemplo, pero solo con un proxy CORS agregado en:
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: Si https://cors-anywhere.herokuapp.com está caído o no está disponible cuando lo prueba, vea a continuación cómo implementar su propio servidor CORS Anywhere en Heroku en solo 2-3 minutos.
El segundo fragmento de código anterior puede acceder a la respuesta con éxito porque toma la URL de solicitud y la cambia a https://cors-anywhere.herokuapp.com/https://example.com simplemente con el prefijo de la URL del proxy, provoca solicitar que se realice a través de ese proxy, que luego:
- Reenvía la solicitud a
https://example.com
.
- Recibe la respuesta de
https://example.com
.
- Agrega el
Access-Control-Allow-Origin
encabezado a la respuesta.
- Pasa esa respuesta, con ese encabezado agregado, de vuelta al código frontend solicitante.
Luego, el navegador permite que el código frontend acceda a la respuesta, porque esa respuesta con el Access-Control-Allow-Origin
encabezado de respuesta es lo que ve el navegador.
Puede ejecutar fácilmente su propio proxy utilizando el código de https://github.com/Rob--W/cors-anywhere/ .
También puede implementar fácilmente su propio proxy en Heroku en literalmente solo 2-3 minutos, con 5 comandos:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Después de ejecutar esos comandos, terminará con su propio servidor CORS Anywhere ejecutándose en, por ejemplo, https://cryptic-headland-94862.herokuapp.com/ . Entonces, en lugar de prefijar su URL de solicitud con https://cors-anywhere.herokuapp.com
, prefije en su lugar con la URL de su propia instancia; por ejemplo, https://cryptic-headland-94862.herokuapp.com/https://example.com .
Entonces, si intenta utilizar https://cors-anywhere.herokuapp.com, encuentra que está inactivo (que a veces lo estará), considere obtener una cuenta de Heroku (si aún no lo hizo) y tome 2 o 3 minutos para realizar los pasos anteriores para implementar su propio servidor CORS Anywhere en Heroku.
Independientemente, ya sea que ejecute el suyo o use https://cors-anywhere.herokuapp.com u otro proxy abierto, esta solución funciona incluso si la solicitud es la que activa los navegadores para hacer una OPTIONS
solicitud de verificación previa CORS , porque en ese caso, el proxy también devuelve los encabezados Access-Control-Allow-Headers
y Access-Control-Allow-Methods
necesarios para que la verificación previa sea exitosa.
Cómo evitar la verificación previa de CORS
El código en la pregunta desencadena una verificación previa CORS, ya que envía un Authorization
encabezado.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Incluso sin eso, el Content-Type: application/json
encabezado también desencadenaría la verificación previa.
Qué significa "verificación previa": antes de que el navegador intente ingresar POST
el código en la pregunta, primero enviará una OPTIONS
solicitud al servidor, para determinar si el servidor está optando por recibir un origen cruzado POST
que incluye los encabezados Authorization
y Content-Type: application/json
.
Funciona bastante bien con un pequeño script curl: obtengo mis datos.
Para realizar una prueba adecuada curl
, debe emular la OPTIONS
solicitud de verificación previa que envía el navegador:
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
reemplazado por cual sea su sign_in
URL real .
La respuesta que el navegador necesita ver de esa OPTIONS
solicitud debe incluir encabezados como este:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Si la OPTIONS
respuesta no incluye esos encabezados, entonces el navegador se detendrá allí y ni siquiera intentará enviar elPOST
solicitud. Además, el código de estado HTTP para la respuesta debe ser 2xx, generalmente 200 o 204. Si se trata de cualquier otro código de estado, el navegador se detendrá allí.
El servidor en la pregunta está respondiendo a la OPTIONS
solicitud con un código de estado 501, lo que aparentemente significa que está tratando de indicar que no implementa soporte para OPTIONS
solicitudes. Otros servidores suelen responder con un código de estado 405 "Método no permitido" en este caso.
Por lo tanto, nunca podrá realizar POST
solicitudes directamente a ese servidor desde su código JavaScript frontend si el servidor responde a esoOPTIONS
solicitud con un 405 o 501 o cualquier otra cosa que no sea 200 o 204 o si no responde con los necesarios encabezados de respuesta.
La forma de evitar desencadenar una verificación previa para el caso en la pregunta sería:
- si el servidor no requirió un
Authorization
encabezado de solicitud sino que (por ejemplo) se basó en datos de autenticación incrustados en el cuerpo de la POST
solicitud o como un parámetro de consulta
- si el servidor no requirió que el
POST
cuerpo tuviera un Content-Type: application/json
tipo de medio, sino que aceptó el POST
cuerpo como application/x-www-form-urlencoded
con un parámetro llamado json
(o lo que sea) cuyo valor son los datos JSON
Cómo corregir “encabezado Access-Control-Allow-Origen no debe ser el comodín” problemas
Recibo otro mensaje de error:
El valor del encabezado 'Access-Control-Allow-Origin' en la respuesta no debe ser el comodín '*' cuando el modo de credenciales de la solicitud es 'incluir'. Por lo tanto, el origen ' http://127.0.0.1:3000 ' no tiene acceso permitido. El modo de credenciales de las solicitudes iniciadas por XMLHttpRequest está controlado por el atributo withCredentials.
Para una solicitud que incluya credenciales, los navegadores no permitirán que el código JavaScript de su interfaz acceda a la respuesta si el valor del Access-Control-Allow-Origin
encabezado de respuesta es *
. En lugar del valor en ese caso debe coincidir exactamente con el origen de su código de interfaz, http://127.0.0.1:3000
.
Ver solicitudes con credenciales y comodines en el artículo de control de acceso HTTP (CORS) de MDN.
Si controla el servidor al que está enviando la solicitud, una forma común de tratar este caso es configurar el servidor para que tome el valor del Origin
encabezado de la solicitud y haga eco / refleje de nuevo en el valor del Access-Control-Allow-Origin
encabezado de respuesta. Por ejemplo, con nginx:
add_header Access-Control-Allow-Origin $http_origin
Pero ese es solo un ejemplo; otros sistemas de servidor (web) proporcionan formas similares de eco de valores de origen.
Estoy usando Chrome También intenté usar ese complemento Chrome CORS
Ese complemento Chrome CORS aparentemente simplemente inyecta un Access-Control-Allow-Origin: *
encabezado en la respuesta que ve el navegador. Si el plugin eran más inteligentes, lo que estaría haciendo es establecer el valor de esa falsa Access-Control-Allow-Origin
cabecera de respuesta al origen real de su interfaz de código JavaScript, http://127.0.0.1:3000
.
Por lo tanto, evite usar ese complemento, incluso para las pruebas. Es solo una distracción. Si desea probar qué respuestas obtiene del servidor sin que el navegador las filtre, es mejor usarlas curl -H
como se indica arriba.
En cuanto al código JavaScript frontend para la fetch(…)
solicitud en la pregunta:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Elimina esas líneas. Los Access-Control-Allow-*
encabezados son encabezados de respuesta . Nunca desea enviarlos en una solicitud. El único efecto que tendrá es activar un navegador para hacer una verificación previa.