Bir REST API'den veri almaya çalışırken istenen kaynakta 'Access-Control-Allow-Origin' başlığı yok

HP Alm'nin REST API'sinden bazı verileri almaya çalışıyorum. Küçük bir curl betiği ile oldukça iyi çalışıyor - verilerimi alıyorum.

Şimdi bunu JavaScript, fetch ve ES6 (aşağı yukarı) ile yapmak daha büyük bir sorun gibi görünüyor. Bu hata mesajını almaya devam ediyorum:

Fetch API yüklenemiyor. Preflight isteğine yanıt gelmiyor erişim kontrolünü geçemiyor: Hiçbir 'Erişim Kontrolü-İzin Ver-Kaynak' başlığı yok istenen kaynak üzerinde mevcut. Köken 'http://127.0.0.1:3000' şudur bu nedenle erişim izni verilmemiştir. Yanıt HTTP durum kodu 501'e sahipti. Eğer opak bir yanıt ihtiyaçlarınızı karşılıyorsa, isteğin modunu şu şekilde ayarlayın Kaynağı CORS devre dışı bırakılmış olarak almak için > 'no-cors'.

Bunun, bu verileri localhost'umdan almaya çalışmamdan kaynaklandığını ve çözümün CORS kullanmak olması gerektiğini anlıyorum. Şimdi bunu gerçekten yaptığımı düşündüm, ama bir şekilde ya başlıkta yazdıklarımı görmezden geliyor ya da sorun başka bir şey mi?

Peki, bir uygulama sorunu var mı? Yanlış mı yapıyorum? Ne yazık ki sunucu kayıtlarını kontrol edemiyorum. Burada gerçekten biraz sıkışmış durumdayım.

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Chrome kullanıyorum. Chrome CORS Eklentisini kullanmayı da denedim, ancak o zaman başka bir hata mesajı alıyorum:

Yanıttaki 'Access-Control-Allow-Origin' başlığının değeri istek'kimlik bilgileri modu olduğunda '*' joker karakteri olmamalıdır 'şunları içerir'. Köken 'http://127.0.0.1:3000' bu nedenle izin verilmez erişim. tarafından başlatılan isteklerin kimlik bilgileri modu XMLHttpRequest, withCredentials niteliği tarafından kontrol edilir.

Çözüm

Bu cevap çok geniş bir alanı kapsamaktadır, bu nedenle üç bölüme ayrılmıştır:

  • "Erişim Kontrolü İzni Yok-Kaynak başlığı "* sorunlarını aşmak için CORS proxy nasıl kullanılır
  • CORS ön uçuşundan nasıl kaçınılır "Access-Control-Allow-Origin başlığı joker karakter olmamalıdır " sorunları nasıl düzeltilir

    *"Access-Control-Allow-Origin başlığı yok " sorunlarını aşmak için bir CORS proxy'si nasıl kullanılır** Ön uç JavaScript kodunuzun istek gönderdiği sunucuyu kontrol etmiyorsanız ve bu sunucudan gelen yanıtla ilgili sorun yalnızca gerekli Access-Control-Allow-Origin başlığının olmamasıysa, isteği bir CORS proxy aracılığıyla yaparak yine de işlerin yürümesini sağlayabilirsiniz. Bunun nasıl çalıştığını göstermek için, önce CORS proxy kullanmayan bazı kodları burada bulabilirsiniz:

const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

Catchbloğunun oraya çarpmasının nedeni, tarayıcının bu kodunhttps://example.comadresinden geri gelen yanıta erişmesini engellemesidir. Tarayıcının bunu yapmasının nedeni, yanıtınAccess-Control-Allow-Origin` yanıt başlığından yoksun olmasıdır. Şimdi, burada tam olarak aynı örnek var ama sadece bir CORS proxy eklenmiş:

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

Not: Eğer https://cors-anywhere.herokuapp.com denediğinizde kapalı veya kullanılamıyorsa, Heroku'da kendi CORS Anywhere sunucunuzu sadece 2-3 dakika içinde nasıl dağıtacağınızı öğrenmek için aşağıya bakın. Yukarıdaki ikinci kod parçacığı yanıta başarıyla erişebilir çünkü istek URL'sini alıp https://cors-anywhere.herokuapp.com/https://example.com-by olarak değiştirmek ve önüne proxy URL'sini eklemek isteğin bu proxy üzerinden yapılmasına neden olur:

  1. İsteği https://example.com adresine yönlendirir.
  2. Yanıtı https://example.com adresinden alır.
  3. Yanıta Access-Control-Allow-Origin başlığını ekler.
  4. Bu yanıtı, eklenen başlıkla birlikte, talep eden ön uç koduna geri iletir. Tarayıcı daha sonra ön uç kodunun yanıta erişmesine izin verir, çünkü Access-Control-Allow-Origin yanıt başlığını içeren bu yanıt tarayıcının gördüğü yanıttır. https://github.com/Rob--W/cors-anywhere/.
Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

Eğer OPTIONS' yanıtı bu başlıkları içermiyorsa, tarayıcı burada duracak vePOST' isteğini göndermeyi asla denemeyecektir. Ayrıca, yanıt için HTTP durum kodu 2xx (genellikle 200 veya 204) olmalıdır. Eğer başka bir durum kodu ise, tarayıcı orada duracaktır. Sorudaki sunucu OPTIONS' isteğine 501 durum koduyla yanıt veriyor, bu da görünüşe göreOPTIONS' istekleri için destek uygulamadığını belirtmeye çalıştığı anlamına geliyor. Diğer sunucular bu durumda genellikle 405 "Method not allowed" durum koduyla yanıt verir. Dolayısıyla, sunucu OPTIONS isteğine 405 veya 501 ya da 200 veya 204 dışında bir yanıt verirse veya bu gerekli yanıt başlıklarıyla yanıt vermezse, ön uç JavaScript kodunuzdan doğrudan bu sunucuya POST istekleri yapamazsınız. Sorudaki durum için bir ön kontrol tetiklemekten kaçınmanın yolu şöyle olacaktır:

  • Sunucu bir Yetkilendirme istek başlığı gerektirmiyorsa, bunun yerine (örneğin) POST isteğinin gövdesine veya bir sorgu parametresi olarak gömülü kimlik doğrulama verilerine güveniyorsa
  • Sunucu POST gövdesinin bir Content-Type: application/json medya türüne sahip olmasını gerektirmiyorsa, bunun yerine POST gövdesini değeri JSON verisi olan json (veya başka bir şey) adlı bir parametre ile application/x-www-form-urlencoded olarak kabul ediyorsa

    *"Access-Control-Allow-Origin başlığı joker karakter olmamalıdır " sorunları nasıl düzeltilir** Başka bir hata mesajı alıyorum:

    Yanıttaki 'Access-Control-Allow-Origin' başlığının değeri istek'kimlik bilgileri modu olduğunda '' joker karakteri olmamalıdır 'şunları içerir'. Köken 'http://127.0.0.1:3000' bu nedenle izin verilmez erişim. tarafından başlatılan isteklerin kimlik bilgileri modu XMLHttpRequest withCredentials niteliği tarafından kontrol edilir. Kimlik bilgilerini içeren bir istek için, Access-Control-Allow-Origin yanıt üstbilgisinin değeri `ise, tarayıcılar ön uç JavaScript kodunuzun yanıta erişmesine izin vermez. Bunun yerine, bu durumda değer ön uç kodunuzun kaynağı olanhttp://127.0.0.1:3000ile tam olarak eşleşmelidir. MDN HTTP erişim denetimi (CORS) makalesinde [*Credentialed requests and wildcards*][1] bölümüne bakın. İsteği gönderdiğiniz sunucuyu kontrol ediyorsanız, bu durumla başa çıkmanın yaygın bir yolu, sunucuyuOriginistek başlığının değerini alacak ve bunuAccess-Control-Allow-Origin` yanıt başlığının değerine geri yansıtacak/yansıtacak şekilde yapılandırmaktır. Örneğin, nginx ile:

add_header Access-Control-Allow-Origin $http_origin

Ancak bu sadece bir örnektir; diğer (web) sunucu sistemleri de orijin değerlerini yankılamak için benzer yollar sağlar.

Chrome kullanıyorum. Ayrıca şu Chrome CORS Eklentisini kullanmayı da denedim Chrome CORS eklentisi görünüşe göre basit bir şekilde Access-Control-Allow-Origin' enjekte ediyor: * başlığını tarayıcının gördüğü yanıta enjekte ediyor. Eğer eklenti daha akıllı olsaydı, yaptığı şey bu sahte Access-Control-Allow-Origin yanıt başlığının değerini ön uç JavaScript kodunuzun gerçek kaynağı olan http://127.0.0.1:3000 olarak ayarlamak olurdu. Bu yüzden test için bile olsa bu eklentiyi kullanmaktan kaçının. Bu sadece dikkat dağıtıcıdır. Tarayıcı filtrelemesi olmadan sunucudan aldığınız yanıtları test etmek istiyorsanız, yukarıdaki gibi curl -H kullanmanız daha iyi olacaktır.

Sorudaki fetch(...) isteği için ön uç JavaScript koduna gelince:

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Şu çizgileri kaldırın. Erişim Kontrolü İzin Ver- başlıkları yanıt* başlıklarıdır. Bunları asla bir istek içinde göndermek istemezsiniz. Bunun tek etkisi bir tarayıcıyı ön kontrol yapması için tetiklemek olacaktır.

Yorumlar (8)

Bu hata, port numarası da dahil olmak üzere istemci URL'si ve sunucu URL'si eşleşmediğinde ortaya çıkar. Bu durumda, çapraz kaynak paylaşımı olan CORS için hizmetinizi etkinleştirmeniz gerekir.

Bir Spring REST hizmeti barındırıyorsanız, bunu Spring Framework'te CORS desteği blog yazısında bulabilirsiniz.

Node.js sunucusu kullanarak bir hizmet barındırıyorsanız

  1. Node.js sunucusunu durdurun.

  2. npm install cors --save

  3. Aşağıdaki satırları server.js dosyanıza ekleyin

    var cors = require('cors')

    app.use(cors()) // Bunu değişken bildiriminden sonra kullanın

Yorumlar (4)

Kaldır şunu:

credentials: 'include',
Yorumlar (0)