javascript - react - Intentando usar fetch and pass en modo: no-cors
react fetch mode no cors (5)
Puedo llegar a este punto final,
http://catfacts-api.appspot.com/api/facts?number=99
través de Postman y devuelve
JSON
Además, estoy usando create-react-app y me gustaría evitar configurar cualquier configuración de servidor.
En mi código de cliente, estoy tratando de usar
fetch
para hacer lo mismo, pero aparece el error:
No hay encabezado ''Access-Control-Allow-Origin'' presente en el recurso solicitado. Por lo tanto, el origen '' http: // localhost: 3000 '' no tiene acceso permitido. Si una respuesta opaca satisface sus necesidades, configure el modo de solicitud en ''no-cors'' para recuperar el recurso con CORS deshabilitado.
Así que estoy tratando de pasar 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
real esté rota, porque cuando elimino el objeto {mode: ''no-cors''} y le proporciono una URL diferente, funciona bien.
También intenté pasar el objeto
{ mode: ''opaque''}
, pero esto devuelve el error original de arriba.
Creo que todo lo que necesito hacer es deshabilitar CORS. ¿Qué me estoy perdiendo?
La solución simple: agregue lo siguiente a la parte superior del archivo php del que solicita los datos.
header("Access-Control-Allow-Origin: *");
Entonces, si eres como yo y estás desarrollando un sitio web en localhost donde estás tratando de obtener datos de Laravel API y usarlos en tu front-end de Vue, y ves este problema, así es como lo resolví:
-
En su proyecto Laravel, ejecute el comando
php artisan make:middleware Cors
. Esto creará laapp/Http/Middleware/Cors.php
para usted. -
Agregue el siguiente código dentro de la función de
handles
enCors.php
:return $next($request) ->header(''Access-Control-Allow-Origin'', ''*'') ->header(''Access-Control-Allow-Methods'', ''GET, POST, PUT, DELETE, OPTIONS'');
-
En
app/Http/kernel.php
, agregue la siguiente entrada en la matriz$routeMiddleware
:‘cors’ => /App/Http/Middleware/Cors::class
(Habría otras entradas en la matriz como
auth
,guest
, etc. También asegúrese de hacerlo enapp/Http/kernel.php
porque también hay otrokernel.php
en Laravel) -
Agregue este middleware en el registro de ruta para todas las rutas donde desea permitir el acceso, de esta manera:
Route::group([''middleware'' => ''cors''], function () { Route::get(''getData'', ''v1/MyController@getData''); Route::get(''getData2'', ''v1/MyController@getData2''); });
-
En el front-end de Vue, asegúrese de llamar a esta API en la función
mounted()
y no endata()
. También asegúrese de usarhttp://
ohttps://
con la URL en su llamadafetch()
.
La solución muy fácil (2 minutos para configurar) es usar
local-ssl-proxy
paquete
local-ssl-proxy
de
npm
El uso es bastante sencillo:
1. Instale el paquete:
npm install -g local-ssl-proxy
2. Mientras ejecuta su
local-server
enmascaré con el
local-ssl-proxy --source 9001 --target 9000
PD:
Reemplace
--target 9000
con el
-- "number of your port"
y
--source 9001
con
--source "number of your port +1"
La solución para mí era simplemente hacerlo del lado del servidor
WebClient
biblioteca 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 idioma del lado del servidor 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);
}
}
Puede ajustarlo a lo que sea su propio caso de uso.
El punto principal es
client.DownloadData()
funcionó sin ningún error CORS.
Por lo general, los problemas de CORS son solo entre sitios web, por lo tanto, está bien hacer solicitudes ''entre sitios'' desde su servidor.
Entonces, la llamada de recuperación de React 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....
)}
mode: ''no-cors''
adición
mode: ''no-cors''
mágicamente no hará que las cosas funcionen.
De hecho, empeora las cosas, porque un efecto que tiene es decirle a los navegadores:
"Bloquee el código JavaScript de mi interfaz para que no vea el contenido del cuerpo de respuesta y los encabezados en todas las circunstancias".
Por supuesto, eso casi nunca es lo que desea.
Lo que sucede con las solicitudes de origen cruzado de JavaScript frontend es que los navegadores de forma predeterminada impiden que el código frontend acceda a los recursos de origen cruzado.
Si un sitio envía
Access-Control-Allow-Origin
en sus respuestas, los navegadores relajarán ese bloqueo y permitirán que su código acceda a la respuesta.
Pero si un sitio no envía un encabezado
Access-Control-Allow-Origin
en sus respuestas, no hay forma de que su código de interfaz pueda acceder directamente a las respuestas desde ese sitio.
En particular, no puede solucionarlo especificando el
mode: ''no-cors''
(de hecho, eso
asegurará que
su código frontend no pueda acceder al contenido de la respuesta).
Sin embargo, una cosa que funcionará es si envía su solicitud a través de un proxy CORS , como este:
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>
Nota: si cuando intenta utilizar https://cors-anywhere.herokuapp.com, encuentra que está inactivo , 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
.
Puedo llegar a este punto final,
http://catfacts-api.appspot.com/api/facts?number=99
través de Postman
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
explica por qué es que, aunque puede acceder a la respuesta con Postman, los navegadores no le permitirán acceder a la respuesta de origen cruzado desde la interfaz Código JavaScript que se ejecuta en una aplicación web a menos que la respuesta incluya un encabezado de respuesta
Access-Control-Allow-Origin
.
http://catfacts-api.appspot.com/api/facts?number=99
no tiene encabezado de respuesta
Access-Control-Allow-Origin
, por lo que no hay forma de que el código de la interfaz pueda acceder al origen cruzado de la respuesta.
Su navegador puede obtener una buena respuesta y puede verla en Postman e incluso en las herramientas del navegador, pero eso no significa que los navegadores lo expongan a su código.
No lo harán, porque no tiene encabezado de respuesta
Access-Control-Allow-Origin
.
Por lo tanto, debe usar un proxy para obtenerlo.
El proxy realiza la solicitud a ese sitio, obtiene la respuesta, agrega el encabezado de respuesta
Access-Control-Allow-Origin
y cualquier otro encabezado CORS necesario, luego lo devuelve a su código de solicitud.
Y esa respuesta con el encabezado
Access-Control-Allow-Origin
agregado es lo que ve el navegador, por lo que el navegador permite que su código frontend realmente acceda a la respuesta.
Así que estoy tratando de pasar un objeto a mi Fetch que deshabilitará CORS
No quieres hacer eso. Para ser claros, cuando dice que desea "deshabilitar CORS", parece que realmente quiere decir que desea deshabilitar la política del mismo origen . CORS en sí mismo es en realidad una forma de hacerlo: CORS es una forma de aflojar la política del mismo origen, no una forma de restringirla.
Pero de todos modos, es cierto que puede, solo en su entorno local, hacer cosas como dar banderas de tiempo de ejecución de su navegador para deshabilitar la seguridad y ejecutar de forma insegura, o puede instalar una extensión de navegador localmente para evitar la política del mismo origen, pero todo eso hace es cambiar la situación solo para usted localmente.
No importa lo que cambie localmente, cualquier otra persona que intente usar su aplicación todavía se encontrará con la política del mismo origen, y no hay forma de que pueda deshabilitarla para otros usuarios de su aplicación.
Lo más probable es que nunca quieras usar el
mode: ''no-cors''
en la práctica, excepto en algunos casos limitados
, e incluso entonces solo si sabes exactamente lo que estás haciendo y cuáles son los efectos.
Eso se debe a que el
mode: ''no-cors''
configuración
mode: ''no-cors''
realmente le dice al navegador es:
"Bloquear mi código JavaScript frontend para que no busque en el contenido del cuerpo de respuesta y los encabezados en todas las circunstancias".
.
En cuanto a los casos en que desea considerar el uso del
mode: ''no-cors''
, vea la respuesta en
¿Qué limitaciones se aplican a las respuestas opacas?
para los detalles
La esencia de esto es que los casos son:
-
En el caso limitado cuando está usando JavaScript para hacer un recurso de otro origen, el contenido de un
<script>
,<link rel=stylesheet>
,<img>
,<video>
,<audio>
,<object>
,<embed>
, o elemento<iframe>
(que funciona porque la inclusión de recursos de origen cruzado está permitida para ellos), pero por alguna razón no desea o no puede hacerlo simplemente haciendo que el marcado del documento use el recurso URL como el atributohref
osrc
para el elemento. -
Cuando lo único que desea hacer con un recurso es almacenarlo en caché. Como se mencionó en la respuesta en ¿Qué limitaciones se aplican a las respuestas opacas? , en la práctica, el escenario que se aplica es cuando usa Service Workers, en cuyo caso la API relevante es la API de almacenamiento en caché .
Pero incluso en esos casos limitados, hay algunas trampas importantes a tener en cuenta; vea la respuesta en ¿Qué limitaciones se aplican a las respuestas opacas? para los detalles
También he tratado de pasar el objeto
{ mode: ''opaque''}
No hay
mode: ''opaque''
solicitud
mode: ''opaque''
: en su lugar,
opaque
es solo una propiedad de la
respuesta
, y los navegadores configuran esa propiedad opaca en las respuestas de las solicitudes enviadas con el modo
no-cors
.
Pero, incidentalmente, la palabra opaco es una señal bastante explícita sobre la naturaleza de la respuesta con la que termina: "opaco" significa que no puede verla.