Permitir el encabezado Access-Control-Allow-Origin mediante la API de recuperación de HTML5

87

Estoy usando la API de recuperación de HTML5.

var request = new Request('https://davidwalsh.name/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});

Puedo usar json normal pero no puedo recuperar los datos de la URL de la API anterior. Lanza error:

La API de recuperación no puede cargar https://davidwalsh.name/demo/arsenal.json . No hay un encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado. Por lo tanto, no se permite el acceso al origen ' http: // localhost '. Si una respuesta opaca satisface sus necesidades, configure el modo de la solicitud en 'no-cors' para obtener el recurso con CORS deshabilitado.

iNikkz
fuente
El servidor de terceros debe configurarlo, no hay nada que pueda hacer en el lado del cliente.
epascarello
@epascarello: Podemos hacerlo del lado del cliente. Detrás de escena, XHR Request está en marcha. Por favor verifique estohttps://davidwalsh.name/fetch
iNikkz

Respuestas:

81

Como dijo epascarello, el servidor que aloja el recurso debe tener CORS habilitado. Lo que puede hacer en el lado del cliente (y probablemente en lo que está pensando) es establecer el modo de recuperación en CORS (aunque creo que esta es la configuración predeterminada):

fetch(request, {mode: 'cors'});

Sin embargo, esto aún requiere que el servidor habilite CORS también y permita que su dominio solicite el recurso.

Consulte la documentación de CORS y este increíble video de Udacity que explica la Política del mismo origen .

También puede usar el modo no-cors en el lado del cliente, pero esto solo le dará una respuesta opaca (no puede leer el cuerpo, pero la respuesta aún puede ser almacenada en caché por un trabajador del servicio o consumida por algunas API, como <img>) :

fetch(request, {mode: 'no-cors'})
.then(function(response) {
  console.log(response); 
}).catch(function(error) {  
  console.log('Request failed', error)  
});
Escalas de David
fuente
2
¿Puede dar más detalles sobre "Sin embargo, esto aún requiere que el servidor habilite CORS también y permita que su dominio solicite el recurso"? He estado buscando instrucciones para hacerlo sin éxito.
jayscript
2
@jayscript el proceso general se ve así: en el cliente, se realiza una solicitud de origen cruzado con javascript. En el caso de la API de recuperación, el modo 'cors' le dice al navegador que está bien realizar esta solicitud. Si en su lugar tuviera el modo 'no-cors', el navegador detendría la solicitud, porque no es el origen de su aplicación. El servidor recibirá la solicitud y responderá. El navegador confirma que la respuesta tiene los encabezados CORS apropiados y, de ser así, permite que se lea la respuesta. Si los encabezados no están presentes, el navegador arrojará un error.
David Scales
1
@jayscript este artículo de MDN entra en detalles. Esencialmente, en su servidor necesita configurar estos encabezados: "Access-Control-Allow-Origin: foo.example ", "Access-Control-Allow-Methods: POST, GET, OPTIONS", "Access-Control-Allow-Headers: X-PINGOTHER, Content-Type ", que habilitan orígenes, métodos y encabezados respectivamente. Por lo general, se usa '*' para el encabezado de origen. También puede consultar este documento de Google y el laboratorio de código asociado para obtener información sobre la API de Fetch: developers.google.com/web/ilt/pwa/working-with-the-fetch-api
David Scales
2
¡Gracias! Eso me ayuda a comprender que es imposible obtener datos del servidor API que tiene un origen diferente cuando el servidor API no contiene ningún encabezado. En el caso particular con el que estaba tratando, tuve acceso al código del servidor API y pude agregar encabezados por mí mismo, lo que permitió la obtención.
jayscript
Esto es tonto, ¿cuál es el problema de seguridad con las NO sendingcookies y, por lo tanto, permitir CORS?
deathangel908
14

Tenía mi código de front-end ejecutándose en http: // localhost: 3000 y mi API (código de backend) ejecutándose en http: // localhost: 5000

Estaba usando fetch API para llamar a la API. Inicialmente, estaba arrojando un error "cors". Luego agregué este código a continuación en mi código de API de backend, lo que permite el origen y el encabezado desde cualquier lugar.

let allowCrossDomain = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', "*");
  res.header('Access-Control-Allow-Headers', "*");
  next();
}
app.use(allowCrossDomain);

Sin embargo, debe restringir los orígenes en el caso de otros entornos como stage, prod.

smsivaprakaash
fuente
20
esta es una respuesta terrible. este es un problema de seguridad masivo. Si está leyendo esto, NO HAGA ESTO.
mjones.udri
1
Esto es válido para la configuración local. Por ejemplo, para hacer una foto rápida. Sí, existe un riesgo de seguridad si lo mismo ocurre con otros entornos desplegables. Para los locales, creo que no. "Sin embargo, debe restringir los orígenes de usted en el caso de otros entornos como escenario, prod"
smsivaprakaash
12

Esto funcionó para mí:

npm install -g local-cors-proxy

Punto final de API que queremos solicitar que tiene problemas de CORS:

https://www.yourdomain.com/test/list

Iniciar Proxy:

lcp --proxyUrl https://www.yourdomain.com

 Proxy Active 

 Proxy Url: http://www.yourdomain.com:28080
 Proxy Partial: proxy
 PORT: 8010

Luego, en su código de cliente, nuevo punto final de API:

http://localhost:8010/proxy/test/list

El resultado final será una solicitud a https://www.yourdomain.ie/test/list sin los problemas de CORS.

VigKam
fuente
Pls hace paralela de que el servidor está funcionando como Windows CMT-del sistema abierto nuevo y ejecutar el código LCP --proxyUrl yourdomain.com
Govarthanan Venunathan
8

Sé que esta es una publicación anterior, pero descubrí que lo que me funcionó para corregir este error fue usar la dirección IP de mi servidor en lugar de usar el nombre de dominio dentro de mi solicitud de búsqueda. Así por ejemplo:

#(original) var request = new Request('https://davidwalsh.name/demo/arsenal.json');
#use IP instead
var request = new Request('https://0.0.0.0/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});
MattG
fuente
1

Si usa nginx, intente esto

#Control-Allow-Origin access

    # Authorization headers aren't passed in CORS preflight (OPTIONS) calls. Always return a 200 for options.
    add_header Access-Control-Allow-Credentials "true" always;
    add_header Access-Control-Allow-Origin "https://URL-WHERE-ORIGIN-FROM-HERE " always;
    add_header Access-Control-Allow-Methods "GET,OPTIONS" always;
    add_header Access-Control-Allow-Headers "x-csrf-token,authorization,content-type,accept,origin,x-requested-with,access-control-allow-origin" always;

    if ($request_method = OPTIONS ) {
        return 200;
    }

Caliari
fuente
-3

Mire https://expressjs.com/en/resources/middleware/cors.html Tiene que usar cors.

Instalar en pc:

$ npm install cors
const cors = require('cors');
app.use(cors());

Tienes que poner este código en tu servidor de nodo.

Ernersto Pastori
fuente
1
¿Cómo puede saber si es el servidor de OP y está escrito en NodeJs?
Marek Szkudelski
Si ha creado un servidor de nodo (modo de desarrollo), puede usar ese método para usar fetch en js.
Ernersto Pastori