Getirme ve geçme modunu kullanmaya çalışıyorum: cors yok


196

http://catfacts-api.appspot.com/api/facts?number=99Postman aracılığıyla bu uç noktaya ulaşabilirim ve geri dönerJSON

Ek olarak, create-react-app kullanıyorum ve herhangi bir sunucu yapılandırması kurmaktan kaçınmak istiyorum.

İstemci kodumda fetchaynı şeyi yapmaya çalışıyorum , ancak şu hatayı alıyorum:

İstenen kaynakta 'Access-Control-Allow-Origin' başlığı yok. Bu nedenle ' http: // localhost: 3000 ' kaynağına erişime izin verilmiyor. Opak bir yanıt ihtiyaçlarınızı karşılıyorsa, CORS devre dışıyken kaynağı almak için isteğin modunu 'no-cors' olarak ayarlayın.

Bu yüzden, CORS'u devre dışı bırakacak bir nesneyi Getirme'me geçirmeye çalışıyorum, şöyle:

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

İlginçtir ki, aldığım hata aslında bu işlevle ilgili bir sözdizimi hatası. fetchGerçekimin bozuk olduğundan emin değilim , çünkü {mode: 'no-cors'} nesnesini kaldırdığımda ve ona farklı bir URL verdiğimde gayet iyi çalışıyor.

Nesneyi de iletmeye çalıştım { mode: 'opaque'}, ancak bu yukarıdan orijinal hatayı döndürüyor.

Tek yapmam gereken CORS'u devre dışı bırakmak olduğuna inanıyorum .. Neyi kaçırıyorum?

Yanıtlar:


345

mode: 'no-cors'sihirli bir şekilde işleri yürütmez. Aslında işleri daha da kötüleştiriyor, çünkü tarayıcılara "Ön uç JavaScript kodumun yanıt gövdesi ve başlıkların içeriğine her koşulda bakmasını engelle" demektir. Tabii ki bunu neredeyse hiç istemezsiniz.

Ön uç JavaScript'ten gelen çapraz kaynak isteklerinde olan şey, tarayıcıların varsayılan olarak ön uç kodunun kaynak çapraz kaynaklara erişmesini engellemesidir. Yanıt Access-Control-Allow-Originveriliyorsa, tarayıcılar bu engellemeyi rahatlatacak ve kodunuzun yanıta erişmesine izin verecektir.

Ancak bir site Access-Control-Allow-Originyanıtlarında hayır gönderirse , ön uç kodunuz o siteden gelen yanıtlara doğrudan erişemez. Özellikle, belirterek bunu düzeltemez mode: 'no-cors'(edeceğiz aslında sağlamak tepki içeriğini erişemez senin ön uç kodu).

Ancak, bir şey olacaktır çalışır: Eğer aracılığıyla isteği göndermek eğer bir CORS vekil böyle:

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>

Not: https://cors-anywhere.herokuapp.com'u kullanmayı denediğinizde, çalışmadığını fark ederseniz, 5 komutla kendi proxy'nizi tam anlamıyla sadece 2-3 dakika içinde Heroku'ya kolayca dağıtabilirsiniz:

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

Bu komutları çalıştırdıktan sonra, örneğin https://cryptic-headland-94862.herokuapp.com/ adresinde çalışan kendi CORS Anywhere sunucunuzla karşılaşacaksınız . Dolayısıyla, istek URL'nizin https://cors-anywhere.herokuapp.comönüne kendi örneğinizin URL'sini eklemek yerine; ör . https://cryptic-headland-94862.herokuapp.com/https://example.com .


http://catfacts-api.appspot.com/api/facts?number=99Postman aracılığıyla bu uç noktaya ulaşabilirim

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS , yanıta Postman ile erişebilseniz bile tarayıcıların ön uçtan çapraz kaynaklı yanıta erişmenize neden izin vermediğini açıklıyor Yanıt bir Access-Control-Allow-Originyanıt başlığı içermediği sürece bir web uygulamasında çalışan JavaScript kodu .

http://catfacts-api.appspot.com/api/facts?number=99Access-Control-Allow-Origin yanıt üstbilgisine sahip değildir , bu nedenle ön uç kodunuzun yanıt çapraz kaynağına erişmesine imkan yoktur.

Tarayıcınız yanıtı alabilir ve bunu Postacı'da ve hatta tarayıcı geliştirmelerinde görebilirsiniz - ancak bu, tarayıcıların onu kodunuza ifşa edeceği anlamına gelmez. Olmaz, çünkü Access-Control-Allow-Originyanıt başlığı yoktur . Yani onu almak için bunun yerine bir proxy kullanmalısınız.

Proxy bu siteye istekte bulunur, yanıtı alır, Access-Control-Allow-Originyanıt başlığını ve gereken diğer CORS başlıklarını ekler , ardından bunu istek kodunuza geri gönderir. Access-Control-Allow-OriginÜstbilgi eklenmiş olan bu yanıt , tarayıcının gördüğü şeydir, böylece tarayıcı ön uç kodunuzun gerçekten yanıta erişmesine izin verir.


Bu yüzden, CORS'u devre dışı bırakacak bir nesneyi Getirme'ime geçirmeye çalışıyorum.

Bunu yapmak istemezsin. Açık olmak gerekirse, "CORS'u devre dışı bırakmak" istediğinizi söylediğinizde, aslında aynı kökenli politikayı devre dışı bırakmak istediğinizi kastetmişsinizdir . CORS'un kendisi aslında bunu yapmanın bir yoludur - CORS, aynı menşeli politikayı kısıtlamanın bir yolu değil, gevşetmenin bir yoludur.

Ancak yine de, - yalnızca yerel ortamınızda - güvenliği devre dışı bırakmak ve güvensiz şekilde çalıştırmak için tarayıcınıza çalışma zamanı bayrakları vermek gibi şeyler yapabileceğiniz veya aynı kaynak politikasını aşmak için yerel olarak bir tarayıcı uzantısı yükleyebileceğiniz doğru, ancak bunların hepsi yerel olarak sizin için durumu değiştirmektir.

Yerel olarak neyi değiştirirseniz değiştirin, uygulamanızı kullanmaya çalışan herhangi biri yine de aynı kaynak politikasına tabi olacaktır ve bunu uygulamanızın diğer kullanıcıları için devre dışı bırakmanın bir yolu yoktur.

Muhtemelen mode: 'no-cors'birkaç sınırlı durum dışında pratikte kullanmak istemezsiniz ve o zaman bile sadece ne yaptığınızı ve etkilerinin ne olduğunu tam olarak biliyorsanız. Bunun nedeni mode: 'no-cors', tarayıcıya aslında "Ön uç JavaScript kodumun yanıt gövdesi ve başlıkların içeriğine her koşulda bakmasını engelle" demesidir. Çoğu durumda, açıkça istediğiniz şey bu değil.


Uzak durumlarda Olarak ne zaman olacağını kullanmayı düşünebilirsiniz mode: 'no-cors'yanıtı şu bkz sınırlamalar opak yanıtları için geçerli ne olacak? detaylar için. İşin özü, davaların şunlar olmasıdır:

  • Eğer bir içine başka orijinli içeriği koymak için JavaScript kullanıyorsanız sınırlı durumda <script>, <link rel=stylesheet>, <img>, <video>, <audio>, <object>, <embed>, veya <iframe>ama nedense sen don' - (kaynakların katıştırma çapraz kökenli olanlar için izin verilir çünkü çalışır) elemanı Bunu, yalnızca belgenin biçimlendirmesinin öğe için hrefveya srcözniteliği olarak kaynak URL'sini kullanmasını sağlayarak yapmak istemez veya yapamazsınız .

  • Bir kaynakla yapmak istediğiniz tek şey onu önbelleğe almak olduğunda. Yanıtta ima edildiği gibi, opak yanıtlar için hangi sınırlamalar geçerlidir? , pratikte geçerli olan senaryo, Hizmet Çalışanları'nı kullandığınız zamandır, bu durumda ilgili API, Önbellek Depolama API'sidir .

Ancak bu sınırlı durumlarda bile, dikkat edilmesi gereken bazı önemli sorunlar vardır; En cevap bkz Ne sınırlamalar opak yanıtları için geçerlidir? detaylar için.


Ben de nesneyi geçmeye çalıştım { mode: 'opaque'}

mode: 'opaque'İstek modu yoktur - opaquebunun yerine yalnızca yanıtın bir özelliğidir ve tarayıcılar no-corsmodla gönderilen isteklerden gelen yanıtlarda bu opak özelliği ayarlar.

Ancak tesadüfen opak kelimesi , sonuçta elde ettiğiniz yanıtın doğası hakkında oldukça açık bir işarettir: "opak", onu göremeyeceğiniz anlamına gelir.


4
cors-anywhereÜretim dışı basit kullanım durumları için geçici çözümü sevin (yani, herkese açık bazı verileri getirmek). Bu yanıt no-cors, OpaqueResponse çok yararlı olmadığı için yaygın olmayan şüphelerimi doğruluyor ; yani "çok sınırlı durumlar"; kimse bana nerelerin no-corsyararlı olduğunu açıklayabilir mi?
Kırmızı Bezelye

1
@TheRedPea Burada cevaba yaptığım güncellemeyi görün (ve ayrıca stackoverflow.com/questions/52569895/… adresinde sorunuza yorum olarak eklediğim )
sidehowbarker

- Ben CORS.js paketiyle benim Ekspres sunucusunu yapılandırmak için gereken github.com/expressjs/cors - ve sonra kaldırmak için gerekli mode: 'no-cors'(Aksi yanıt boş olurdu) getirme isteğinden
James L.

2
CORS vekili harika. Herkese açık dosyalara erişimi engellemenin bir "güvenlik" önlemi olarak görülmesine şaşırdım. Bilgisayar korsanı perspektifinden dolaşmak çok, çok kolay ve bu tam olarak bunu yapıyor. Bu gerçekten iyi oyuncular için bir güçlük.
Seph Reed

Aynı API'yi kullanan farklı istemcilerin kodunu oluşturuyorum. Eğitimler için kullanıyorum. Kodu basit tutmak ve kullanıcıların onunla oynamasına izin vermek istiyorum. No-cros kullanmam gerekiyor.
profimedica

6

Yani benim gibiyseniz ve localhost'ta Laravel API'den veri almaya ve bunu Vue ön ucunuzda kullanmaya çalıştığınız bir web sitesi geliştiriyorsanız ve bu sorunu görüyorsanız, işte bunu nasıl çözdüm:

  1. Laravel projenizde komutu çalıştırın php artisan make:middleware Cors. Bu app/Http/Middleware/Cors.phpsizin için yaratacaktır .
  2. Aşağıdaki kodu handlesişlevin içine ekleyin Cors.php:

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    
  3. İçinde app/Http/kernel.php, $routeMiddlewarediziye aşağıdaki girişi ekleyin :

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

    (Dizide auth, guestvb. Gibi başka girişler de olabilirdi. Ayrıca bunu yaptığınızdan emin olun app/Http/kernel.phpçünkü kernel.phpLaravel'de başka bir tane daha var)

  4. Erişime izin vermek istediğiniz tüm yollar için rota kaydına bu ara yazılımı ekleyin, örneğin:

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
    
  5. Vue ön ucunda, bu API'yi mounted()işlev olarak çağırdığınızdan ve içinde değil data(). Ayrıca emin Kullanmak yapmak http://veya https://sizin URL ile fetch()görüşme.

Pete Houston'ın blog makalesine tam kredi .


3

Basit çözüm: Aşağıdakileri, verileri talep ettiğiniz php dosyasının en üstüne ekleyin.

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

15
Mümkün olan en az güvenlik miktarını istiyorsanız bu çok iyi bir fikir :).
Heretic Maymun

peki ya resim hotlink
user889030

2

Benim için çözüm sadece sunucu tarafında yapmaktı

WebClientVerileri almak için C # kitaplığını kullandım (benim durumumda görüntü verisiydi) ve istemciye geri gönderdim. Muhtemelen seçtiğiniz sunucu tarafı dilinde çok benzer bir şey vardır.

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

Kendi kullanım durumunuz ne olursa olsun onu değiştirebilirsiniz. Ana nokta, client.DownloadData()herhangi bir CORS hatası olmadan çalışılır. Tipik olarak CORS sorunları yalnızca web siteleri arasındadır, bu nedenle sunucunuzdan 'siteler arası' isteklerde bulunmanızda bir sorun yoktur.

Sonra React getirme çağrısı şu kadar basittir:

//React component

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

       // Do more stuff....
    )}

2

Express'i arka uç olarak kullanıyorsanız, sadece cors yüklemeniz ve app.use (cors ()); içinde içe aktarmanız ve kullanmanız gerekir. Çözülmezse, bağlantı noktalarını değiştirmeyi deneyin. Bağlantı noktalarını değiştirdikten sonra kesinlikle çözülecektir


1

Çok kolay çözüm (yapılandırmaya 2 dakika) yerel-ssl-proxy paketini kullanmaktır.npm

Kullanım oldukça basittir:
1. Paketi kurun: npm install -g local-ssl-proxy
2. local-serverMaskenizi çalıştırırkenlocal-ssl-proxy --source 9001 --target 9000

Not: Değiştir --target 9000ile -- "number of your port"ve --source 9001ile--source "number of your port +1"


1
Uygulamamı gerçek telefon cihazında kullanırken sorun yaşıyorum. Çözümünüz bu durum için faydalı mı?
Hamid Araghi

@HamidAraghi Şimdi, geliştirme amaçları için proxy sunucusunun hatadan gerçekten etkilenen cihaz üzerinde çalışması gerektiğini
varsayıyorum
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.