Essayer d'utiliser la récupération et la transmission en mode: no-cors

167

Je peux atteindre ce point de terminaison, http://catfacts-api.appspot.com/api/facts?number=99via Postman et il revientJSON

De plus, j'utilise create-react-app et je voudrais éviter de configurer une configuration de serveur.

Dans mon code client, j'essaie d'utiliser fetchpour faire la même chose, mais j'obtiens l'erreur:

Aucun en-tête «Access-Control-Allow-Origin» n'est présent sur la ressource demandée. L' accès à l' origine ' http: // localhost: 3000 ' n'est donc pas autorisé. Si une réponse opaque répond à vos besoins, définissez le mode de la requête sur «no-cors» pour récupérer la ressource avec CORS désactivé.

J'essaye donc de passer un objet, à mon Fetch qui désactivera CORS, comme ceci:

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;
  });

Il est intéressant de noter que l'erreur que j'obtiens est en fait une erreur de syntaxe avec cette fonction. Je ne suis pas sûr que mon réel fetchsoit cassé, car lorsque je supprime l'objet {mode: 'no-cors'} et que je le fournis avec une URL différente, cela fonctionne très bien.

J'ai aussi essayé de passer dans l'objet { mode: 'opaque'} , mais cela renvoie l'erreur d'origine d'en haut.

Je crois que tout ce que j'ai à faire est de désactiver CORS. Que me manque-t-il?

dwww
la source

Réponses:

292

mode: 'no-cors'ne fera pas fonctionner les choses comme par magie. En fait, cela aggrave les choses, car l'un de ses effets est de dire aux navigateurs: "Empêchez mon code JavaScript frontal de consulter le contenu du corps de la réponse et des en-têtes en toutes circonstances." Bien sûr, vous ne le voulez presque jamais.

Ce qui se passe avec les requêtes cross-origin de JavaScript frontend, c'est que les navigateurs bloquent par défaut le code frontend pour accéder aux ressources cross-origin. S'il Access-Control-Allow-Originy a une réponse, les navigateurs relâcheront ce blocage et permettront à votre code d'accéder à la réponse.

Mais si un site envoie non Access-Control-Allow-Origindans ses réponses, votre code frontend ne peut pas accéder directement aux réponses de ce site. En particulier, vous ne pouvez pas le résoudre en spécifiant mode: 'no-cors'(en fait, cela garantira votre code frontend ne pourra pas accéder au contenu de la réponse).

Cependant, une chose qui va travailler: si vous envoyez votre demande par l' intermédiaire d' un proxy CORS , comme ceci:

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>

Remarque: si lorsque vous essayez d'utiliser https://cors-anywhere.herokuapp.com, vous trouvez qu'il est en panne , vous pouvez également facilement déployer votre propre proxy sur Heroku en seulement 2-3 minutes, avec 5 commandes:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

Après avoir exécuté ces commandes, vous vous retrouverez avec votre propre serveur CORS Anywhere fonctionnant à, par exemple, https://cryptic-headland-94862.herokuapp.com/ . Ainsi, plutôt que de préfixer votre URL de requête avec https://cors-anywhere.herokuapp.com, préfixez-la plutôt avec l'URL de votre propre instance; par exemple, https://cryptic-headland-94862.herokuapp.com/https://example.com .


Je peux atteindre ce point de terminaison, http://catfacts-api.appspot.com/api/facts?number=99via Postman

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explique pourquoi même si vous pouvez accéder à la réponse avec Postman, les navigateurs ne vous permettront pas d'accéder à l'origine croisée de la réponse depuis le frontend Code JavaScript exécuté dans une application Web, sauf si la réponse inclut un en- Access-Control-Allow-Origintête de réponse.

http://catfacts-api.appspot.com/api/facts?number=99 n'a pasAccess-Control-Allow-Origin tête de réponse, il n'y a donc aucun moyen pour votre code frontal d'accéder à l'origine croisée de la réponse.

Votre navigateur peut obtenir la réponse correctement et vous pouvez la voir dans Postman et même dans les outils de développement du navigateur - mais cela ne signifie pas que les navigateurs l'exposeront à votre code. Ils ne le feront pas, car il n'a pas d'en- Access-Control-Allow-Origintête de réponse. Vous devez donc utiliser à la place un proxy pour l'obtenir.

Le proxy fait la demande à ce site, obtient la réponse, ajoute l'en- Access-Control-Allow-Origintête de réponse et tous les autres en-têtes CORS nécessaires, puis le renvoie à votre code de demande. Et cette réponse avec l'en- Access-Control-Allow-Origintête ajouté est ce que le navigateur voit, de sorte que le navigateur laisse votre code frontal accéder réellement à la réponse.


J'essaye donc de passer un objet, à mon Fetch qui désactivera CORS

Tu ne veux pas faire ça. Pour être clair, lorsque vous dites que vous voulez «désactiver CORS», il semble que vous vouliez vraiment désactiver la politique de même origine . CORS lui-même est en fait un moyen d'y parvenir - CORS est un moyen d'assouplir la politique de même origine, pas un moyen de la restreindre.

Mais de toute façon, il est vrai que vous pouvez - dans votre environnement local seulement - faire des choses comme donner des indicateurs d'exécution à votre navigateur pour désactiver la sécurité et s'exécuter de manière non sécurisée, ou vous pouvez installer une extension de navigateur localement pour contourner la politique de même origine, mais tout cela fait est de changer la situation juste pour vous localement.

Peu importe ce que vous modifiez localement, toute autre personne qui essaiera d'utiliser votre application continuera de se heurter à la politique de même origine, et vous ne pouvez en aucun cas la désactiver pour les autres utilisateurs de votre application.

Vous ne voudrez probablement jamais l'utiliser mode: 'no-cors'en pratique, sauf dans quelques cas limités , et même dans ce cas uniquement si vous savez exactement ce que vous faites et quels sont les effets. C'est parce que ce que le paramètre mode: 'no-cors'dit réellement au navigateur est: "Empêchez mon code JavaScript frontal de regarder dans le contenu du corps de la réponse et des en-têtes en toutes circonstances." Dans la plupart des cas, ce n'est évidemment pas ce que vous voulez.


En ce qui concerne les cas où vous voudriez envisager d'utiliser mode: 'no-cors', consultez la réponse à Quelles limites s'appliquent aux réponses opaques? pour les détails. L'essentiel est que les cas sont:

  • Dans le cas limité où vous utilisez JavaScript pour mettre du contenu d'une autre origine dans un <script>,<link rel=stylesheet> , <img>, <video>, <audio>, <object>, <embed>ou <iframe>élément (qui fonctionne parce que l' incorporation des ressources Croiser d'origine est autorisée pour les) - mais pour une raison quelconque , vous n » Vous voulez ou ne pouvez pas faire cela simplement en demandant au balisage du document d'utiliser l'URL de la ressource comme attribut hrefou srcpour l'élément.

  • Lorsque la seule chose que vous voulez faire avec une ressource est de la mettre en cache. Comme évoqué dans la réponse Quelles limites s'appliquent aux réponses opaques? , en pratique, le scénario qui s'applique est lorsque vous utilisez des Service Workers, auquel cas l'API pertinente est l' API Cache Storage .

Mais même dans ces cas limités, il y a quelques pièges importants à prendre en compte; voir la réponse à Quelles limites s'appliquent aux réponses opaques? pour les détails.


J'ai aussi essayé de passer dans l'objet { mode: 'opaque'}

Il n'y a pas de mode: 'opaque'mode de demande - il opaques'agit plutôt d'une propriété de la réponse , et les navigateurs définissent cette propriété opaque sur les réponses des demandes envoyées avec le no-corsmode.

Mais accessoirement le mot opaque est un signal assez explicite sur la nature de la réponse que vous obtenez: «opaque» signifie que vous ne pouvez pas le voir.

soiree
la source
4
J'adore la cors-anywheresolution de contournement pour les cas d'utilisation simples non-prod (c'est-à-dire la récupération de données accessibles au public). Cette réponse confirme mon soupçon qui no-corsn'est pas commun car son OpaqueResponse n'est pas très utile; c'est-à-dire "cas très limités"; quelqu'un peut-il m'expliquer des exemples où cela no-corsest utile?
The Red Pea
1
@TheRedPea Voir la mise à jour que j'ai apportée à la réponse ici (et que j'ai également ajoutée en tant que commentaires pour votre question sur stackoverflow.com/questions/52569895/… )
Sideshowbarker
J'avais besoin de configurer mon serveur Express avec le package CORS.js - github.com/expressjs/cors - puis je devais supprimer mode: 'no-cors'de la demande de récupération (sinon la réponse serait vide)
James L.
le proxy CORS est génial. Je suis étonné que cela soit considéré comme une mesure de «sécurité» pour bloquer l'accès aux fichiers publics du tout. C'est tellement facile de se déplacer du point de vue d'un pirate informatique, et c'est exactement ce que cela fait. C'est vraiment un problème pour les bons acteurs.
Seph Reed
Je génère le code de différents clients consommant la même API. Je l'utilise pour les formations. Je veux garder le code simple et laisser les utilisateurs jouer avec. J'ai besoin d'utiliser no-cros.
profimedica
6

Donc, si vous êtes comme moi et que vous développez un site Web sur localhost où vous essayez de récupérer des données de l'API Laravel et de les utiliser dans votre front-end Vue, et que vous voyez ce problème, voici comment je l'ai résolu:

  1. Dans votre projet Laravel, exécutez la commande php artisan make:middleware Cors. Cela créera app/Http/Middleware/Cors.phppour vous.
  2. Ajoutez le code suivant à l'intérieur de la handlesfonction dans Cors.php:

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  3. Dans app/Http/kernel.php, ajoutez l'entrée suivante dans le $routeMiddlewaretableau:

    cors => \App\Http\Middleware\Cors::class

    (Il y aurait d'autres entrées dans le tableau comme auth, guestetc. Assurez-vous également que vous faites cela app/Http/kernel.phpcar il y en a une autre kernel.phpaussi dans Laravel)

  4. Ajoutez ce middleware lors de l'enregistrement des routes pour toutes les routes auxquelles vous souhaitez autoriser l'accès, comme ceci:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
  5. Dans Vue front-end, assurez-vous d'appeler cette API en mounted()fonction et non en data(). Assurez-vous également d'utiliser http://ou https://avec l'URL dans votre fetch()appel.

Crédits complets de l' article de blog de Pete Houston .

point net
la source
2

La solution simple: ajoutez ce qui suit tout en haut du fichier php à partir duquel vous demandez les données.

header("Access-Control-Allow-Origin: *");

Code vraiment sympa
la source
8
C'est une très bonne idée si vous voulez le moins de sécurité possible :).
Heretic Monkey
qu'en est-il de l'image hotlink
user889030
1

La solution pour moi était de le faire juste côté serveur

J'ai utilisé la WebClientbibliothèque C # pour obtenir les données (dans mon cas, c'était des données d'image) et les renvoyer au client. Il y a probablement quelque chose de très similaire dans la langue que vous avez choisie côté serveur.

//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);
    }
}

Vous pouvez l'adapter à votre propre cas d'utilisation. Le point principal estclient.DownloadData() travaillé sans aucune erreur CORS. En règle générale, les problèmes CORS ne concernent que les sites Web, il est donc normal de faire des requêtes «intersites» à partir de votre serveur.

Ensuite, l'appel de récupération React est aussi simple que:

//React component

fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {            
        method: 'GET',
    })
    .then(resp => resp.json() as Promise<ItemImage>)
    .then(imgResponse => {

       // Do more stuff....
    )}
Stuart Aitken
la source
1

Une solution très simple (2 minutes de configuration) consiste à utiliser le package local-ssl-proxy denpm

L'utilisation est simple:
1. Installez le package: npm install -g local-ssl-proxy
2. Tout en exécutant votre local-servermasque avec lelocal-ssl-proxy --source 9001 --target 9000

PS: remplacer --target 9000par le -- "number of your port"et --source 9001par--source "number of your port +1"

Volna
la source
1
J'ai des difficultés à utiliser mon application sur un appareil téléphonique réel. Votre solution est-elle utile dans ce cas?
Hamid Araghi
@HamidAraghi Je suppose que maintenant, puisque pour les besoins du développement, le serveur proxy devrait fonctionner sur l'appareil qui est réellement affecté par l'erreur
volna