jQuery xml hatası 'İstenen kaynakta' Access-Control-Allow-Origin 'başlığı yok.'


89

Http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml adresinde bulunan bir xml dosyasını okumak ve xml'yi ayrıştırmak ve para birimleri arasındaki değerleri dönüştürmek için kullanın.

Şimdiye kadar, xml'yi okumak için oldukça basit olan aşağıdaki kodu buldum, ancak aşağıdaki hatayı alıyorum.

XMLHttpRequest **** yükleyemiyor. İstenen kaynakta 'Access-Control-Allow-Origin' başlığı yok. Bu nedenle ' http://run.jsbin.com ' kaynağına erişime izin verilmiyor.

$(document).ready( 
    function() {     
        $.ajax({          
            type:  'GET',
            url:   'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml',
            dataType: 'xml',              
            success: function(xml){
                alert('aaa');
            }
         });
    }
);

Kodumda yanlış bir şey görmüyorum, bu yüzden birinin kodumda neyi yanlış yaptığımı ve bunu nasıl düzeltebileceğimi göstermesini umuyorum.



hata tam olarak neyin yanlış olduğunu belirtir, kelime kelime. Kodunuz gayet iyi, sorun erişmekte olduğunuz sunucuda.
Kevin B

Yanıtlar:


163

Aynı orijinli politika nedeniyle, http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xmladresinde konuşlandırılan bir dosyadan ajax çağrısı yapamazsınız .http://run.jsbin.com


Kaynak (diğer adıyla orijin ) sayfası ve hedef URL farklı etki alanlarında ( run.jsbin.comve www.ecb.europa.eu) olduğundan, kodunuz aslında sıradan olmayan bir Web Alanları Arası (CORS) isteği yapmaya çalışıyor GET.

Birkaç kelimeyle, aynı kaynak politikası , tarayıcıların sadece HTML sayfasının aynı etki alanındaki hizmetlere ajax çağrılarına izin vermesi gerektiğini söylüyor .


Misal:

A sayfa http://www.example.com/myPage.htmlcan sadece doğrudan altındadır hizmetlerini talep http://www.example.comgibi http://www.example.com/api/myService. Hizmet başka bir alanda barındırılıyorsa (örneğin http://www.ok.com/api/myService), tarayıcı aramayı doğrudan yapmaz (beklediğiniz gibi). Bunun yerine, bir CORS talebinde bulunmaya çalışacaktır.

Kısaca söylemek gerekirse, farklı etki alanlarında bir (CORS) isteği * gerçekleştirmek için tarayıcınız:

  • OriginOrijinal isteğe bir başlık ekler (değer olarak sayfanın etki alanıyla) ve bunu her zamanki gibi gerçekleştirir; ve sonra
  • Yalnızca sunucu yanıtı o isteğine içerir (yeterli başlıklarını Access-Control-Allow-Originolan bir tanesi ) CORS talep sağlayan, göz çağrısı (neredeyse ** HTML sayfası aynı etki de olsaydı olurdu tam yolu) tamamlayacak.
    • Beklenen başlıklar gelmezse, tarayıcı basitçe pes eder (size yaptığı gibi).


* Yukarıdaki tasvir etmektedir Bir adımlar basit bir duzgun olarak istek, GEThiçbir fantezi başlıklarıyla. (A gibi istek basit değilse POSTile application/jsoniçerik türü gibi), tarayıcı bunu yerine getirmeden önce, bir an tutun ve edecek ilk olarak bir göndereceğiz OPTIONShedef URL'ye isteği. Yukarıdaki gibi, yalnızca bu OPTIONSisteğe verilen yanıt CORS başlıklarını içeriyorsa devam edecektir . Bu OPTIONSçağrı, ön kontrol isteği olarak bilinir .
** Neredeyse söylüyorum çünkü normal aramalar ile CORS aramaları arasında başka farklılıklar var. Önemli bir nokta, bazı başlıkların, yanıtta mevcut olsalar bile ,Access-Control-Expose-Headers başlığa dahil edilmemişlerse tarayıcı tarafından alınmayacağıdır .


Nasıl düzeltilir?

Sadece bir yazım hatası mıydı? Bazen JavaScript kodunun hedef etki alanında yalnızca bir yazım hatası vardır. Kontrol ettin mi? Sayfa www.example.comyerindeyse, yalnızca düzenli aramalar yapacaktır www.example.com! Tarayıcı tarafından farklı alan adları gibi diğer URL'ler, api.example.comhatta example.comveya www.example.com:8080bunlar olarak kabul edilir ! Evet, bağlantı noktası farklıysa, o zaman farklı bir etki alanıdır!

Başlıkları ekleyin. CORS'u etkinleştirmenin en basit yolu Access-Control-Allow-Origin, sunucunun yanıtlarına gerekli başlıkları (as ) eklemektir . (Her sunucunun / dilin bunu yapmanın bir yolu vardır - buradan bazı çözümleri kontrol edin .)

Son çare: Hizmete sunucu tarafında erişiminiz yoksa, onu da yansıtabilir ( ters proxy'ler gibi araçlar aracılığıyla ) ve gerekli tüm başlıkları buraya dahil edebilirsiniz.


2
Teşekkürler, bu çok fazla bilgi. Şimdi devam etmek için gerekli araştırmayı yapabilirim.
Bazinga777

1
Merhaba acdcjunior, erişmek istediğim web hizmetini nasıl yansıtırım?
Franva

2
@Franva Bir HTTP sunucusu kurmanız (örn. Tomcat, PHP ile Apache, ASP ile IIS) ve oraya her istek için gerçek hizmete (yansıttığınız hizmet) bir soket açan bir sayfa yerleştirmeniz gerekecek, gerçek verileri ister ve ardından yanıt olarak verir. Elbette bunu kod aracılığıyla yapacaksınız (Java, PHP, ASP, vb.).
acdcjunior

@acdcjunior Anlayışım doğruysa lütfen beni düzeltin. Doğrudan tarayıcıya bir URL girersem, Erişim-Kontrol-İzin Verme-Kaynak olmadan otomatik olarak yeni etki alanı url'sine yönlendirecektir . Örneğin, WIF kullanırken, kullanıcı ilk kez oturum açtığında üçüncü taraf oturum açma sayfasına yönlendirilecektir.
machinarium

Ne demek istediğini anlıyorum ama cevap (Bir şey yanlış var ise söyle) çalışacağım eğer @machinarium emin değilim: Eğer tarayıcının adres çubuğundaki URL'yi, varlığı veya yokluğunu girerseniz Access-Control-Allow-Origino URL yıllarda başlıklar hiç önemli değil - tarayıcı URL'yi her zamanki gibi açacaktır. Aynı kökenli politika (ve Access-Control-Allow-Originbaşlık gereksinimi ) yalnızca Ajax çağrıları için geçerlidir.
acdcjunior

29

Sunucunuzda php etkinse, bunu yapmanın bir tür hack-tastic yolu vardır. Bu satırı değiştirin:

url:   'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml',

bu satıra:

url: '/path/to/phpscript.php',

ve sonra php betiğinde (file_get_contents () işlevini kullanma izniniz varsa):

<?php

header('Content-type: application/xml');
echo file_get_contents("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");

?>

Bu url'nin farklı bir kaynaktan gelip gelmediğini Php aldırmıyor gibi görünüyor. Dediğim gibi, bu karmaşık bir cevap ve eminim ki bunda bir sorun var, ama bende işe yarıyor.

Düzenleme: Sonucu php'de önbelleğe almak istiyorsanız, kullanacağınız php dosyası:

<?php

$cacheName = 'somefile.xml.cache';
// generate the cache version if it doesn't exist or it's too old!
$ageInSeconds = 3600; // one hour
if(!file_exists($cacheName) || filemtime($cacheName) > time() + $ageInSeconds) {
  $contents = file_get_contents('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
  file_put_contents($cacheName, $contents);
}

$xml = simplexml_load_file($cacheName);

header('Content-type: application/xml');
echo $xml;

?>

Önbelleğe alma kodu buradan alınır .


3
Daha da iyi bir çözüm, XML dosyasını sunucu tarafında önbelleğe almak ve file_get_contentsaramayı yalnızca en son XML dosyası yeterince tarihli ise gerçekleştirmek olacaktır. Ayrıca, Content-Type başlığınızı da unutmayın :-)
sffc

Bu yanıta tökezledi. Soru: PHP dosyası GET verilerini alıp söz konusu URL'ye göndermeyi nasıl biliyor? Bu, POST ile gönderilen verilerle de çalışır mı?
mpdc

Göndermiyor. Dosyayı alır ve yerel olarak kaydeder, sonra o dosya yerel olarak talep ettiğiniz php dosyasıymış gibi yayar. Yerel olarak önbelleğe alınan dosya verilen maksimum yaştan daha eski ise, başka bir kopyasını alır ve kaydeder.
Düşünce
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.