422 votes

Essayer d'utiliser fetch et pass en mode : no-cors

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

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

Dans mon code client, j'essaie d'utiliser fetch pour faire la même chose, mais je reçois l'erreur :

L'en-tête "Access-Control-Allow-Origin" n'est pas présent dans le message demandé. demandée. Origine ' http://localhost:3000 n'est donc pas autorisé accès. Si une réponse opaque répond à vos besoins, définissez l'attribut à "no-cors" pour récupérer la ressource sans CORS.

J'essaie 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 je reçois est en fait une erreur de syntaxe avec cette fonction. Je ne suis pas sûr que mon fetch est cassé, car lorsque je supprime l'objet { mode : 'no-cors' } et que je lui fournis une URL différente, tout fonctionne parfaitement.

J'ai également essayé de passer dans l'objet { mode: 'opaque'} mais cela renvoie l'erreur originale ci-dessus.

Je pense que tout ce que je dois faire est de désactiver CORS Qu'est-ce que je rate ?

1 votes

695voto

sideshowbarker Points 29042

mode: 'no-cors' ne fera pas fonctionner les choses par magie. En fait, il aggrave les choses, car il a pour effet de dire aux navigateurs , "Empêcher mon code JavaScript frontal de regarder le contenu du corps de la réponse et des en-têtes en toutes circonstances." Bien sûr, vous ne voulez presque jamais ça.

Ce qui se passe avec les demandes d'origine croisée provenant du JavaScript frontal, c'est que les navigateurs bloquent par défaut le code frontal pour l'accès aux ressources d'origine croisée. Si Access-Control-Allow-Origin est dans une réponse, alors les navigateurs relâcheront ce blocage et permettront à votre code d'accéder à la réponse.

Mais si un site n'envoie pas Access-Control-Allow-Origin dans ses réponses, votre code frontal ne peut pas accéder directement aux réponses de ce site. En particulier, vous ne pouvez pas résoudre ce problème en spécifiant mode: 'no-cors' (en fait, ce sera assurer votre code frontal ne peut pas accéder au contenu de la réponse).

Cependant, une chose que sera travail : si vous envoyez votre demande par un proxy CORS .

Vous pouvez également déployer facilement votre propre proxy sur Heroku en 2 ou 3 minutes seulement, à l'aide de 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 à l'adresse suivante, par exemple, https://cryptic-headland-94862.herokuapp.com/ .

Faites précéder l'URL de votre demande de l'URL de votre proxy ; par exemple :

https://cryptic-headland-94862.herokuapp.com/https://example.com

L'ajout de l'URL du proxy en tant que préfixe fait que la demande est effectuée par le biais de votre proxy qui, à son tour, fait le nécessaire :

  1. Transférer la demande à https://example.com .
  2. Reçoit la réponse de https://example.com .
  3. Ajoute le Access-Control-Allow-Origin dans la réponse.
  4. Transmet cette réponse, avec cet en-tête ajouté, au code frontal demandeur.

Le navigateur permet ensuite au code frontal d'accéder à la réponse, car cette réponse avec l'attribut Access-Control-Allow-Origin L'en-tête de réponse est ce que le navigateur voit.

Cela fonctionne même si la requête déclenche un contrôle préalable CORS de la part des navigateurs. OPTIONS car, dans ce cas, le proxy renvoie également la requête Access-Control-Allow-Headers y Access-Control-Allow-Methods les en-têtes nécessaires à la réussite du contrôle en amont.


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

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explique pourquoi, bien que vous puissiez accéder à la réponse avec Postman, les navigateurs ne vous laisseront pas accéder à la réponse par le biais d'un code JavaScript frontal s'exécutant dans une application Web, à moins que la réponse n'inclue une balise Access-Control-Allow-Origin en-tête de réponse.

http://catfacts-api.appspot.com/api/facts?number=99 n'a pas Access-Control-Allow-Origin de sorte qu'il n'y a aucun moyen pour votre code frontal d'accéder à la réponse en dehors de l'origine.

Votre navigateur peut recevoir la réponse sans problème 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 de Access-Control-Allow-Origin en-tête de réponse. Vous devez donc utiliser un proxy pour l'obtenir.

Le proxy envoie la demande à ce site, reçoit la réponse, ajoute le nom de l'utilisateur et le mot de passe. Access-Control-Allow-Origin et tout autre en-tête CORS nécessaire, puis le renvoie à votre code demandeur. Et cette réponse avec l'en-tête Access-Control-Allow-Origin ajouté est ce que le navigateur voit. Le navigateur laisse donc votre code frontal accéder à la réponse.


J'essaie donc de passer un objet à mon Fetch qui désactivera CORS.

Vous ne voulez pas faire ça. Pour être clair, lorsque vous dites que vous voulez "désactiver CORS", il semble que vous vouliez en fait désactiver les éléments suivants la politique de la même origine . CORS lui-même est en fait un moyen de le faire - CORS est un moyen d'assouplir la politique du "same-origin", pas un moyen de la restreindre.

Quoi qu'il en soit, il est vrai que vous pouvez - dans votre environnement local uniquement - faire des choses comme donner à votre navigateur des drapeaux d'exécution pour désactiver la sécurité et fonctionner de manière non sécurisée, ou vous pouvez installer une extension de navigateur localement pour contourner la politique de l'origine identique, mais tout cela ne fait que changer la situation juste pour vous localement.

Peu importe ce que vous modifiez localement, toute autre personne essayant d'utiliser votre application se heurtera toujours à la politique de l'origine identique, et il n'y a aucun moyen de la désactiver pour les autres utilisateurs de votre application.

Vous ne voudrez probablement jamais utiliser mode: 'no-cors' en pratique, sauf dans quelques cas limités et encore, seulement si vous savez exactement ce que vous faites et quels en sont les effets. C'est parce que le réglage mode: 'no-cors' dit en fait au navigateur est, "Empêcher mon code JavaScript frontal de regarder 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 serait vous pouvez envisager d'utiliser mode: 'no-cors' voir la réponse à l'adresse suivante Quelles sont les limitations applicables aux réponses opaques ? pour les détails. L'essentiel est que les cas sont :

  • Dans le cas limité où vous utilisez JavaScript pour placer du contenu provenant d'une autre origine dans un fichier de type <script> , <link rel=stylesheet> , <img> , <video> , <audio> , <object> , <embed> ou <iframe> (ce qui fonctionne parce que l'incorporation de ressources à travers l'origine est autorisée pour ces éléments) - mais pour une raison quelconque, vous ne voulez ou ne pouvez pas le faire simplement en faisant en sorte que le balisage du document utilise l'URL de la ressource comme l'élément href o src de l'élément.

  • Lorsque la seule chose que vous voulez faire avec une ressource est de la mettre en cache. Comme il est fait allusion dans la réponse Quelles sont les limitations applicables aux réponses opaques ? Dans la pratique, le scénario qui s'applique est celui où vous utilisez des Service Workers, auquel cas l'API pertinente est l'API API de stockage des caches .

Mais même dans ces cas limités, il faut être conscient de certains écueils importants ; voir la réponse à Quelles sont les limitations applicables aux réponses opaques ? pour les détails.


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

Il n'y a pas mode: 'opaque' mode de demande - opaque est au contraire une simple propriété de l réponse et les navigateurs définissent cette propriété opaque sur les réponses aux demandes envoyées avec l'extension no-cors mode.

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 la voir.

4 votes

J'aime le cors-anywhere solution de contournement pour les cas simples d'utilisation non-prod (i.e. récupérer des données disponibles publiquement). Cette réponse confirme mon soupçon que no-cors n'est pas courant car son OpaqueResponse n'est pas très utile ; c'est-à-dire "des cas très limités" ; quelqu'un peut-il explique-moi exemples où no-cors est utile ?

1 votes

@TheRedPea Voir la mise à jour que j'ai apportée à la réponse ici (et que j'ai également ajoutée en commentaire de votre question à l'adresse suivante stackoverflow.com/questions/52569895/ )

0 votes

J'ai dû configurer mon serveur Express avec le paquet CORS.js. github.com/expressjs/cors - et ensuite j'ai dû enlever mode: 'no-cors' de la requête de récupération (sinon la réponse serait vide)

10voto

Varnit Rohilla Points 41

Si vous utilisez Express comme back-end, il vous suffit d'installer cors, de l'importer et de l'utiliser dans app.use(cors()) ;. Si le problème n'est pas résolu, essayez de changer de port. Il sera sûrement résolu après avoir changé de port.

1 votes

Je me souviens de ma classe de dernière année de collège & aucun autre groupe n'a réussi à faire fonctionner ce système, sauf le nôtre Il s'agit d'une solution simple. Voici un guide plus complet : stackabuse.com/handling-cors-with-node-js

8voto

dotNET Points 5290

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.php pour vous.

  2. Ajoutez le code suivant dans le fichier handles fonction dans Cors.php :

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

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

    (Il y aurait d'autres entrées dans le tableau comme auth , guest etc. Assurez-vous également que vous faites cela dans app/Http/kernel.php parce qu'il y a un autre kernel.php aussi dans Laravel)

  4. Ajoutez ce middleware à l'enregistrement des routes pour toutes les routes auxquelles vous voulez 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 le front-end Vue, assurez-vous d'appeler cette API dans mounted() et non dans la fonction data() . Veillez également à utiliser http:// o https:// avec l'URL dans votre fetch() appeler.

Tous les crédits à Pete Houston's article de blog .

5voto

volna Points 513

Une solution très simple (2 min à configurer) est d'utiliser local-ssl-proxy paquet de npm

L'utilisation est simple et directe :
1. Installez le paquet : npm install -g local-ssl-proxy
2. Pendant l'exécution de votre local-server le masquer avec le local-ssl-proxy --source 9001 --target 9000

P.S : Remplacer --target 9000 avec le -- "number of your port" y --source 9001 con --source "number of your port +1"

1 votes

J'ai des problèmes pour utiliser mon application sur un téléphone réel. Votre solution est-elle utile dans ce cas ?

0 votes

@HamidAraghi Je suppose que maintenant, puisque pour les besoins du développement, le serveur proxy devrait fonctionner sur le dispositif qui est réellement affecté par l'erreur.

4voto

Stuart Aitken Points 58

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

J'ai utilisé le C# WebClient pour récupérer les données (dans mon cas, il s'agissait de données d'image) et les renvoyer au client. Il y a probablement quelque chose de très similaire dans le langage côté serveur que vous avez choisi.

//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 est client.DownloadData() a fonctionné sans aucune erreur CORS. En général, les problèmes de CORS ne concernent que les sites Web entre eux, d'où la possibilité d'effectuer des requêtes "intersites" à partir de votre serveur.

Ensuite, l'appel React fetch 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....
    )}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X