Puedo acceder a este endpoint, http://catfacts-api.appspot.com/api/facts?number=99
a través de Postman y me devuelve JSON
.
Además, estoy usando create-react-app y me gustaría evitar la configuración del servidor.
En mi código de cliente estoy tratando de usar fetch
para hacer lo mismo, pero me da el error:
No está presente la cabecera Access-Control-Allow-Origin' en el recurso solicitado
recurso solicitado. El origen 'http://localhost:3000' no está por tanto permitido el acceso. Si una respuesta opaca sirve a sus necesidades, configure la solicitud's a > no-cors' para obtener el recurso con CORS desactivado.
Así que estoy tratando de pasar en un objeto, a mi Fetch que deshabilitar CORS, así:
fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
.then(blob => blob.json())
.then(data => {
console.table(data);
return data;
})
.catch(e => {
console.log(e);
return e;
});
Curiosamente el error que obtengo es en realidad un error de sintaxis con esta función. No estoy seguro de que mi fetch
esté roto, porque cuando quito el objeto { mode: 'no-cors' }, y lo suministro con una URL diferente, funciona bien.
También he intentado pasar el objeto { mode: 'opaque'}
, pero esto devuelve el error original de arriba.
Creo que lo único que tengo que hacer es desactivar CORS. ¿Qué me falta?
Añadir mode: 'no-cors'no hará que las cosas funcionen mágicamente. De hecho, empeora las cosas, porque uno de los efectos que tiene es decirle a los navegadores, *"Bloquea mi código JavaScript del frontend para que no vea el contenido del cuerpo de la respuesta y las cabeceras bajo ninguna circunstancia "* Por supuesto, eso casi nunca es lo que quieres. Lo que ocurre con las peticiones de origen cruzado del JavaScript del frontend es que los navegadores bloquean por defecto el código del frontend para que no acceda a los recursos de origen cruzado. Si un sitio envía
Access-Control-Allow-Originen sus respuestas, los navegadores relajarán ese bloqueo y permitirán que tu código acceda a la respuesta. Pero si un sitio no envía ninguna cabecera
Access-Control-Allow-Originen sus respuestas, no hay forma de que tu código frontend pueda acceder directamente a las respuestas de ese sitio. En particular, no puedes arreglarlo especificando
mode: 'no-cors'` (de hecho eso asegura que tu código frontend no puede acceder al contenido de la respuesta).
Sin embargo, algo que funcionará es si envías tu petición a través de [un proxy CORS][1], como esto
begin snippet: js hide: false console: true babel: false -->
var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
targetUrl = 'http://catfacts-api.appspot.com/api/facts?number=99'
fetch(proxyUrl + targetUrl)
.then(blob => blob.json())
.then(data => {
console.table(data);
document.querySelector("pre").innerHTML = JSON.stringify(data, null, 2);
return data;
})
.catch(e => {
console.log(e);
return e;
});
<pre></pre>
-->!-- end snippet -->
Nota: si cuando vas a intentar usar https
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
https://cors-anywhere.herokuapp.com
, prefiérela con la URL de tu propia instancia; por ejemplo, https://cryptic-headland-94862.herokuapp.com/https://example.com.Puedo llegar a este punto final,
http://catfacts-api.appspot.com/api/facts?number=99
a través de Postman https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explica por qué, aunque puedes acceder a la respuesta con Postman, los navegadores no te permiten acceder a la respuesta a través del origen desde el código JavaScript del frontend que se ejecuta en una aplicación web, a menos que la respuesta incluya una cabecera de respuestaAccess-Control-Allow-Origin
. http://catfacts-api.appspot.com/api/facts?number=99 no tiene una cabecera de respuesta "Access-Control-Allow-Origin", por lo que no hay forma de que el código frontal pueda acceder a la respuesta a través del origen. Tu navegador puede obtener la respuesta sin problemas y puedes verla en Postman e incluso en las herramientas de desarrollo del navegador, pero eso no significa que los navegadores la expongan a tu código. No lo harán, porque no tiene cabecera de respuestaAccess-Control-Allow-Origin
. Así que debes usar un proxy para conseguirlo. El proxy hace la petición a ese sitio, obtiene la respuesta, añade la cabecera de respuestaAccess-Control-Allow-Origin
y cualquier otra cabecera CORS necesaria, y luego la devuelve a tu código solicitante. Y esa respuesta con la cabeceraAccess-Control-Allow-Origin
añadida es lo que ve el navegador, por lo que el navegador permite que tu código frontend acceda realmente a la respuesta.Así que estoy tratando de pasar un objeto, a mi Fetch que deshabilitará CORS Usted no quiere hacer eso. Para ser claros, cuando dices que quieres "deshabilitar CORS" parece que en realidad quieres decir que quieres deshabilitar la política de mismo origen. El propio CORS es en realidad una forma de hacer eso - CORS es una forma de aflojar la política del mismo origen, no una forma de restringirla. Pero de todos modos, es cierto que puedes - sólo en tu entorno local - hacer cosas como dar a tu navegador banderas de tiempo de ejecución para desactivar la seguridad y ejecutarlo de forma insegura, o puedes instalar una extensión del navegador localmente para evitar la política de mismo origen, pero todo eso hace que la situación cambie sólo para ti localmente. No importa lo que cambies localmente, cualquier otra persona que intente usar tu aplicación seguirá encontrándose con la política del mismo origen, y no hay manera de que puedas desactivar eso para otros usuarios de tu aplicación. Lo más probable es que nunca quieras usar `mode: 'no-cors'en la práctica, excepto en unos pocos casos limitados, e incluso entonces sólo si sabes exactamente lo que estás haciendo y cuáles son los efectos. Esto se debe a que lo que el ajuste de
mode: 'no-cors'
realmente le dice al navegador es, "Bloquea mi código JavaScript del frontend para que no mire el contenido del cuerpo de la respuesta y las cabeceras bajo ninguna circunstancia " En la mayoría de los casos eso no es, obviamente, lo que usted quiere.En cuanto a los casos en los que usted querría considerar el uso de
mode: 'no-cors'
, vea la respuesta en https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790 para los detalles. Lo esencial es que los casos son:
- En el caso limitado de que estés usando JavaScript para hacer que un recurso de otro origen sea el contenido de un elemento
<script>
,<link rel=stylesheet>
,<img>
,<video>
,<audio>
,<object>
,<embed>
, o<iframe>(lo que funciona porque la incrustación de recursos a través del origen está permitida para ellos) - pero por alguna razón no quieres o no puedes hacerlo simplemente haciendo que el marcado del documento utilice la URL del recurso como el atributo
hrefo
src` para el elemento.Cuando lo único que se quiere hacer con un recurso es almacenarlo en caché. Como se alude en la respuesta de https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790, en la práctica el escenario al que se aplica es cuando se utilizan Service Workers, en cuyo caso la API relevante es la Cache Storage API. *Pero incluso en esos casos limitados, hay algunos problemas importantes que hay que tener en cuenta; véase la respuesta en https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790* para los detalles.
También he intentado pasar el objeto
{ mode: 'opaque'}
. No hay ningún modo de petición{mode: 'opaque'
-opaque
es en cambio sólo una propiedad de la respuesta, y los navegadores establecen esa propiedad opaque en las respuestas de las peticiones enviadas con el modono-cors
. Pero, por cierto, la palabra "opaco" es una señal bastante explícita sobre la naturaleza de la respuesta que se obtiene: "opaco" significa que no puedes verlo.
La solución para mí fue hacerlo del lado del servidor
Utilicé la librería C# WebClient
para obtener los datos (en mi caso eran datos de imágenes) y enviarlos de vuelta al cliente. Probablemente haya algo muy similar en el lenguaje del lado del servidor que hayas elegido.
//Server side, api controller
[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
ItemImage image = new ItemImage();
using(WebClient client = new WebClient()){
image.Bytes = client.DownloadData(url);
return Ok(image);
}
}
Usted puede ajustar a lo que su propio caso de uso es. El punto principal es que client.DownloadData()
funcionó sin ningún error CORS. Típicamente los problemas de CORS son sólo entre sitios web, de ahí que esté bien hacer 'cross-site' peticiones desde su servidor.
Entonces la llamada React fetch es tan simple como:
//React component
fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {
method: 'GET',
})
.then(resp => resp.json() as Promise<ItemImage>)
.then(imgResponse => {
// Do more stuff....
)}
Una solución muy sencilla (2 minutos de configuración) es utilizar el paquete local-ssl-proxy de npm
.
El uso es bastante sencillo:
npm install -g local-ssl-proxy
servidor local
enmascárelo con el local-ssl-proxy --source 9001 --target 9000
P.S: Reemplace --target 9000
con el -- "número de su puerto"y
--source 9001con
--source "número de su puerto +1"`.