Proberen om fetch en pass te gebruiken in mode: no-cors

Ik kan dit eindpunt, http://catfacts-api.appspot.com/api/facts?number=99 benaderen via Postman en het retourneert JSON

Bovendien gebruik ik create-react-app en wil ik het opzetten van een server configuratie vermijden.

In mijn client code probeer ik fetch te gebruiken om hetzelfde te doen, maar ik krijg de foutmelding:

No 'Access-Control-Allow-Origin' header is aanwezig op de gevraagde bron. Origin 'http://localhost:3000' is daarom niet toegestaan toegang. Als een ondoorzichtig antwoord uw behoeften dient, stel het verzoek's mode op 'no-cors' om de bron op te halen met CORS uitgeschakeld.

Dus ik probeer een object door te geven aan mijn Fetch dat CORS uitschakelt, zoals dit:

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

Interessant genoeg is de fout die ik krijg eigenlijk een syntaxisfout met deze functie. Ik weet niet zeker of mijn eigenlijke fetch kapot is, want als ik het { mode: 'no-cors' } object verwijder, en het een andere URL geef werkt het prima.

Ik heb ook geprobeerd om het object { mode: 'opaque'} in te voeren, maar dit geeft de originele fout van hierboven.

Ik geloof dat alles wat ik moet doen is CORS uitschakelen. Wat zie ik over het hoofd?

Het toevoegen van mode: 'no-cors' zal de dingen niet op magische wijze laten werken. In feite maakt het dingen erger, omdat een effect dat het heeft is om browsers te vertellen, "Blokkeer mijn frontend JavaScript code van het kijken naar de inhoud van het antwoord lichaam en headers onder alle omstandigheden. " Natuurlijk is dat bijna nooit wat je wilt. Wat er gebeurt met cross-origin verzoeken van frontend JavaScript is dat browsers standaard frontend code blokkeren van cross-origin toegang tot bronnen. Als een site Access-Control-Allow-Origin meestuurt in zijn antwoorden, dan zullen browsers die blokkade versoepelen en jouw code toegang geven tot het antwoord. Maar als een site geen Access-Control-Allow-Origin header meestuurt in zijn antwoorden, dan is er geen enkele manier waarop je frontend code direct toegang kan krijgen tot antwoorden van die site. In het bijzonder, je kunt het niet oplossen door mode: 'no-cors' te specificeren (in feite zal dat zorgen dat je frontend code geen toegang heeft tot de inhoud van het antwoord). Echter, een ding dat wel werkt is als je je verzoek via [een CORS proxy][1] stuurt, zoals dit:

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>

Note: als je https://cors-anywhere.herokuapp.com probeert te gebruiken, vind je dat het down is, je kunt ook gemakkelijk je eigen proxy deployen naar Heroku in letterlijk slechts 2-3 minuten, met 5 commando's:

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

Na het uitvoeren van deze commando's, zul je eindigen met je eigen CORS Anywhere server draaiend op, bijvoorbeeld, https://cryptic-headland-94862.herokuapp.com/. Dus in plaats van het voorvoegsel van uw verzoek URL met https://cors-anywhere.herokuapp.com, voorvoegsel het in plaats daarvan met de URL voor uw eigen instantie; bijvoorbeeld, https://cryptic-headland-94862.herokuapp.com/https://example.com.

Ik kan dit eindpunt, http://catfacts-api.appspot.com/api/facts?number=99 bereiken via Postman https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS verklaart hoe het komt dat, ook al kun je het antwoord benaderen met Postman, browsers je geen toegang geven tot het antwoord cross-origin van frontend JavaScript code die draait in een web app tenzij het antwoord een Access-Control-Allow-Origin response header bevat. http://catfacts-api.appspot.com/api/facts?number=99 heeft geen Access-Control-Allow-Origin header, dus er is geen manier waarop je frontend code toegang kan krijgen tot het antwoord cross-origin. Je browser kan het antwoord prima krijgen en je kunt het zien in Postman en zelfs in browser devtools-maar dat betekent niet dat browsers het zullen tonen aan je code. Dat doen ze niet, omdat het geen Access-Control-Allow-Origin response header heeft. Dus moet je in plaats daarvan een proxy gebruiken om het te krijgen. De proxy doet het verzoek naar die site, krijgt het antwoord, voegt de Access-Control-Allow-Origin header toe en eventuele andere CORS headers die nodig zijn, en stuurt dat dan terug naar je aanvragende code. En dat antwoord met de Access-Control-Allow-Origin header toegevoegd is wat de browser ziet, dus de browser laat je frontend code daadwerkelijk toegang krijgen tot het antwoord.

Dus ik probeer een object door te geven, aan mijn Fetch die CORS uitschakelt Dat wil je niet doen. Om duidelijk te zijn, wanneer je zegt dat je "CORS wilt uitschakelen" lijkt het erop dat je eigenlijk bedoelt dat je de same-origin policy wilt uitschakelen. CORS zelf is eigenlijk een manier om dat te doen - CORS is een manier om het same-origin beleid losser te maken, niet een manier om het te beperken. Maar hoe dan ook, het is waar dat je - alleen in je lokale omgeving - dingen kunt doen zoals je browser runtime flags geven om beveiliging uit te schakelen en onveilig te draaien, of je kunt lokaal een browserextensie installeren om het same-origin beleid te omzeilen, maar dat verandert alleen maar de situatie voor jou lokaal. Het maakt niet uit wat je lokaal verandert, iemand anders die je app probeert te gebruiken zal nog steeds tegen de same-origin policy aanlopen, en er is geen manier om dat uit te schakelen voor andere gebruikers van je app. U wilt waarschijnlijk nooit mode: 'no-cors' gebruiken in de praktijk, behalve in een paar beperkte gevallen, en zelfs dan alleen als u precies weet wat u doet en wat de effecten zijn. Dat komt omdat het instellen van mode: 'no-cors' eigenlijk tegen de browser zegt, "Blokkeer mijn frontend JavaScript code van het kijken naar de inhoud van de response body en headers onder alle omstandigheden. " In de meeste gevallen is dat natuurlijk echt niet wat je wilt.

Wat betreft de gevallen waarin je zou willen overwegen om mode: 'no-cors' te gebruiken, zie het antwoord op https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790 voor de details. De essentie ervan is dat de gevallen zijn:

  • In het beperkte geval dat je JavaScript gebruikt om een bron van een andere oorsprong de inhoud te maken van een <script>, ,, <amp-video>, <amp-audio>, ,, of <iframe> element (wat werkt omdat embedden van bronnen cross-origin is toegestaan voor die) - maar om een of andere reden wil of kun je dat niet doen door de markup van het document de bron URL te laten gebruiken als het href of src attribuut voor het element.
  • Als het enige wat je met een resource wilt doen is deze te cachen. Zoals aangegeven in het antwoord op https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790, is in de praktijk het scenario waarop dit van toepassing is, wanneer je Service Workers gebruikt, in welk geval de API die relevant is, de Cache Storage API is. Maar zelfs in die beperkte gevallen, zijn er enkele belangrijke gotchas om bewust van te zijn; zie het antwoord op https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses/39109790#39109790 voor de details.

    Ik heb ook geprobeerd om het object { mode: 'opaque'} in te geven. Er is geen mode: 'opaque' verzoek modus - opaque is in plaats daarvan gewoon een eigenschap van het antwoord, en browsers stellen die ondoorzichtige eigenschap in op antwoorden van verzoeken die zijn verzonden met de no-cors modus. Maar overigens is het woord *opaque` een vrij expliciet signaal over de aard van het antwoord dat je krijgt: "opaque" betekent dat je het niet kunt zien.

Commentaren (5)

De oplossing voor mij was om het gewoon server side te doen

Ik gebruikte de C# WebClient bibliotheek om de gegevens op te halen (in mijn geval waren het afbeeldingsgegevens) en terug te sturen naar de client. Er is waarschijnlijk iets soortgelijks in de server-side taal van jouw keuze.

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

Je kunt het aanpassen aan je eigen gebruikssituatie. Het belangrijkste punt is dat client.DownloadData() werkte zonder CORS-fouten. Normaal gesproken zijn CORS problemen alleen tussen websites, vandaar dat het goed is om 'cross-site' verzoeken te doen vanaf je server.

Dan is de React fetch call zo simpel als:

//React component

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

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

Zeer gemakkelijke oplossing (2 min om te configureren) is om het local-ssl-proxy pakket van npm te gebruiken

Het gebruik is rechttoe rechtaan:
1. Installeer het pakket: npm install -g local-ssl-proxy
2. Tijdens het draaien van je local-server maskeer deze met de local-ssl-proxy --source 9001 --target 9000

P.S: Vervang -target 9000 door de -- "nummer van je poort" en -source 9001 door -source "nummer van je poort +1"

Commentaren (2)