Versuch, fetch und pass im Modus: no-cors zu verwenden

Ich kann diesen Endpunkt, http://catfacts-api.appspot.com/api/facts?number=99 über Postman ansprechen und er gibt JSON zurück

Außerdem verwende ich create-react-app und möchte die Einrichtung einer Serverkonfiguration vermeiden.

In meinem Client-Code versuche ich, fetch zu verwenden, um das Gleiche zu tun, aber ich erhalte den Fehler:

No 'Access-Control-Allow-Origin' header is present on the requested Ressource. Herkunft 'http://localhost:3000' ist daher nicht erlaubt Zugriff. Wenn eine undurchsichtige Antwort Ihren Bedürfnissen entspricht, setzen Sie den Request's Modus auf 'no-cors', um die Ressource mit deaktiviertem CORS abzurufen.

Ich versuche also, ein Objekt an mein Fetch zu übergeben, das CORS deaktiviert, etwa so:

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

Interessanterweise ist der Fehler, den ich bekomme, eigentlich ein Syntaxfehler in dieser Funktion. Ich bin mir nicht sicher, ob mein eigentliches "Fetch" kaputt ist, denn wenn ich das Objekt { mode: 'no-cors' } entferne und es mit einer anderen URL versehe, funktioniert es ganz gut.

Ich habe auch versucht, das Objekt "{ mode: 'opaque'}" zu übergeben, aber das gibt den ursprünglichen Fehler von oben zurück.

Ich glaube, alles, was ich tun muss, ist CORS zu deaktivieren. Was übersehe ich?

Das Hinzufügen von mode: 'no-cors' wird die Dinge nicht auf magische Weise zum Laufen bringen. In der Tat macht es die Dinge noch schlimmer, weil ein Effekt ist es zu sagen, Browser, "Blockieren Sie meine Frontend-JavaScript-Code von Blick auf den Inhalt der Antwort Körper und Header unter allen Umständen. " Natürlich ist das fast nie, was Sie wollen. Was bei herkunftsübergreifenden Anfragen von Frontend-JavaScript passiert, ist, dass die Browser standardmäßig den Frontend-Code vom Zugriff auf herkunftsübergreifende Ressourcen abhalten. Wenn eine Website Access-Control-Allow-Origin in ihren Antworten sendet, dann lockern die Browser diese Blockierung und erlauben Ihrem Code den Zugriff auf die Antwort. Wenn eine Website jedoch keinen Access-Control-Allow-Origin-Header in ihren Antworten sendet, gibt es keine Möglichkeit, dass Ihr Frontend-Code direkt auf Antworten von dieser Website zugreifen kann. Insbesondere können Sie das nicht beheben, indem Sie mode: 'no-cors' angeben (in der Tat wird das sicherstellen, dass Ihr Frontend-Code nicht auf den Inhalt der Antwort zugreifen kann). Eine Sache, die jedoch funktionieren wird, ist, wenn Sie Ihre Anfrage durch einen CORS-Proxy senden, wie dies:

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>

Hinweis: Wenn Sie versuchen, https://cors-anywhere.herokuapp.com zu verwenden, und feststellen, dass es nicht funktioniert, können Sie auch ganz einfach Ihren eigenen Proxy auf Heroku bereitstellen, und zwar in buchstäblich nur 2-3 Minuten und mit 5 Befehlen:

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

Nachdem Sie diese Befehle ausgeführt haben, haben Sie Ihren eigenen CORS-Anywhere-Server, der z. B. auf https://cryptic-headland-94862.herokuapp.com/ läuft. Anstatt also Ihrer Anfrage-URL https://cors-anywhere.herokuapp.com voranzustellen, stellen Sie ihr stattdessen die URL für Ihre eigene Instanz voran, z.B. https://cryptic-headland-94862.herokuapp.com/https://example.com.

Ich kann diesen Endpunkt, http://catfacts-api.appspot.com/api/facts?number=99 über Postman erreichen https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS erklärt, warum Sie zwar mit Postman auf die Antwort zugreifen können, die Browser Ihnen aber keinen ursprungsübergreifenden Zugriff auf die Antwort von Frontend-JavaScript-Code in einer Webanwendung gestatten, es sei denn, die Antwort enthält einen Response-Header "Access-Control-Allow-Origin". http://catfacts-api.appspot.com/api/facts?number=99 hat keinen "Access-Control-Allow-Origin"-Response-Header, so dass es keine Möglichkeit gibt, dass Ihr Frontend-Code auf die Antwort herkunftsübergreifend zugreifen kann. Ihr Browser kann die Antwort problemlos abrufen und Sie können sie in Postman und sogar in den Browser-Devtools sehen - aber das bedeutet nicht, dass die Browser sie für Ihren Code freigeben. Das werden sie nicht, weil die Antwort keinen "Access-Control-Allow-Origin"-Header hat. Also müssen Sie stattdessen einen Proxy verwenden, um sie zu erhalten. Der Proxy stellt die Anfrage an diese Seite, erhält die Antwort, fügt den "Access-Control-Allow-Origin"-Antwort-Header und alle anderen benötigten CORS-Header hinzu und gibt diese dann an Ihren anfragenden Code zurück. Und diese Antwort mit dem hinzugefügten "Access-Control-Allow-Origin"-Header ist das, was der Browser sieht, so dass der Browser Ihren Frontend-Code tatsächlich auf die Antwort zugreifen lässt.

Ich versuche also, ein Objekt an mein Fetch zu übergeben, das CORS deaktiviert. Das wollen Sie nicht tun. Um das klarzustellen, wenn Sie sagen, Sie wollen "CORS deaktivieren", dann meinen Sie wohl, dass Sie die Same-Origin-Policy deaktivieren wollen. CORS selbst ist eigentlich eine Möglichkeit, das zu tun - CORS ist eine Möglichkeit, die Same-Origin-Policy zu lockern, nicht eine Möglichkeit, sie einzuschränken. Aber wie dem auch sei, es stimmt, dass Sie - nur in Ihrer lokalen Umgebung - Dinge tun können, wie Ihrem Browser Laufzeit-Flags zu geben, um die Sicherheit zu deaktivieren und unsicher zu laufen, oder Sie können eine Browser-Erweiterung lokal installieren, um die Same-Origin-Policy zu umgehen, aber alles, was das bewirkt, ist, die Situation nur für Sie lokal zu ändern. Egal, was Sie lokal ändern, jeder andere, der versucht, Ihre Anwendung zu verwenden, wird immer noch auf die Same-Origin-Policy stoßen, und es gibt keine Möglichkeit, diese für andere Benutzer Ihrer Anwendung zu deaktivieren. Sie werden mode: 'no-cors' in der Praxis höchstwahrscheinlich nie verwenden wollen, außer in einigen wenigen Fällen, und selbst dann nur, wenn Sie genau wissen, was Sie tun und welche Auswirkungen das hat. Das liegt daran, dass die Einstellung mode: 'no-cors' dem Browser eigentlich sagt: "Verhindern Sie unter allen Umständen, dass mein Frontend-JavaScript-Code den Inhalt des Antwortkörpers und der Kopfzeilen einsehen kann. " In den meisten Fällen ist das natürlich nicht das, was Sie wollen.

Was die Fälle angeht, in denen Sie die Verwendung von "mode: 'no-cors'`" in Betracht ziehen sollten, finden Sie die Details in der Antwort auf https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790. Das Wesentliche ist, dass die Fälle sind:

  • In dem begrenzten Fall, dass Sie JavaScript verwenden, um eine Ressource von einem anderen Ursprung zum Inhalt eines <script>, ,, <amp-video>, <amp-audio>, ,, oder <iframe>Element (was funktioniert, weil das Einbetten von Ressourcen über den Ursprung hinweg für diese erlaubt ist) - aber aus irgendeinem Grund wollen oder können Sie das nicht einfach tun, indem Sie das Markup des Dokuments die Ressourcen-URL alshrefodersrc`-Attribut für das Element verwenden lassen.
  • Wenn das Einzige, was Sie mit einer Ressource tun wollen, darin besteht, sie zwischenzuspeichern. Wie in der Antwort auf https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790 angedeutet, ist in der Praxis das Szenario, auf das dies zutrifft, die Verwendung von Service Workern, in diesem Fall ist die API, die relevant ist, die Cache Storage API. Aber selbst in diesen begrenzten Fällen gibt es einige wichtige Probleme, die zu beachten sind; siehe die Antwort unter https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790 für die Details.

    Ich habe auch versucht, das Objekt { mode: 'opaque'} zu übergeben. Es gibt keinen mode: 'opaque' Anfragemodus - opaque ist stattdessen nur eine Eigenschaft der Antwort, und Browser setzen diese opaque-Eigenschaft auf Antworten von Anfragen, die mit dem no-cors-Modus gesendet wurden. Aber nebenbei bemerkt ist das Wort opak ein ziemlich eindeutiges Signal über die Art der Antwort, die Sie am Ende erhalten: "Opak" bedeutet, dass man sie nicht sehen kann.

Kommentare (5)

Die Lösung für mich war, es einfach serverseitig zu machen

Ich benutzte die C# WebClient-Bibliothek, um die Daten (in meinem Fall waren es Bilddaten) abzurufen und sie an den Client zurückzuschicken. Wahrscheinlich gibt es etwas sehr ähnliches in der von Ihnen gewählten serverseitigen Sprache.

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

Sie können es an Ihren eigenen Anwendungsfall anpassen. Der wichtigste Punkt ist, dass client.DownloadData() ohne CORS-Fehler funktioniert. Normalerweise gibt es CORS-Probleme nur zwischen Websites, daher ist es in Ordnung, von Ihrem Server aus 'cross-site' Anfragen zu stellen.

Dann ist der React-Fetch-Aufruf so einfach wie:

//React component

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

       // Do more stuff....
    )}
Kommentare (0)

Eine sehr einfache Lösung (2 Minuten für die Konfiguration) ist die Verwendung des Pakets local-ssl-proxy von npm.

Die Benutzung ist ziemlich einfach:

  1. Installieren Sie das Paket: npm install -g local-ssl-proxy
  2. Während Sie Ihren local-server laufen lassen, maskieren Sie ihn mit dem local-ssl-proxy --source 9001 --target 9000

P.S: Ersetzen Sie --target 9000 durch die -- "Nummer Ihres Ports" und --source 9001 durch --source "Nummer Ihres Ports +1"

Kommentare (2)