web-dev-qa-db-ja.com

'jQuery xmlエラー'いい 'Access-Control-Allow-Origin'ヘッダが要求されたリソースに存在します。

私はこの個人的なプロジェクトに取り組んでいます。XMLファイルを読みたいのです。 http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml そしてxmlを解析して通貨間で値を変換するためにそれを使用します。

これまでのところ私はxmlを読むためにかなり基本的な以下のコードを思い付きました、しかし私は以下のエラーを得ます。

XMLHttpRequestは****をロードできません。要求されたリソースに 'Access-Control-Allow-Origin'ヘッダーがありません。 Origin ' http://run.jsbin.com 'はアクセスを許可されていません。

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

私は自分のコードに何か問題があるとは思わないので、自分のコードで何が間違っているのか、そしてどうすればそれを修正できるのかを誰かが指摘できると期待しています。

89
Bazinga777

same-Origin policy のため、http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xmlにデプロイされたファイルからhttp://run.jsbin.comにajax呼び出しを行うことはできません。


ソース(別名Origin)ページとtarget URLが異なるドメイン(run.jsbin.comおよびwww.ecb.europa.eu)にあるため、コードは実際に- クロスドメイン(CORS)リクエスト、通常のGETではありません。

一言で言えば、same-Originポリシーは、ブラウザーがHTMLページのsame domainでサービスへのajax呼び出しのみを許可するべきだと言っています。


例:

http://www.example.com/myPage.htmlのページは、http://www.example.comのようなhttp://www.example.com/api/myServiceにあるサービスのみを直接要求できます。サービスが別のドメイン(http://www.ok.com/api/myServiceなど)でホストされている場合、ブラウザーは(予想どおり)直接呼び出しを行いません。代わりに、CORS要求を作成しようとします。

簡単に言うと、異なるドメインで(CORS)リクエストを実行するには、ブラウザは次のようにします。

  • 元のリクエストに(ページのドメインを値として)Originヘッダーを含め、通常どおり実行します。その後
  • 次の場合のみそのリクエストに対するサーバーresponseには 適切なヘッダー(Access-Control-Allow-Origin isone CORSリクエストを許可すると、ブラウズは呼び出しを完了します(HTMLページが同じドメインにある場合とほぼ同じ方法で)。
    • 予想されるヘッダーが届かない場合、ブラウザは単にあきらめます(あなたがしたように)。


*上記は、simpleリクエストの手順を示しています。たとえば、空想ヘッダーのない通常のGETなどです。リクエストが単純でない場合(コンテンツタイプとしてapplication/jsonを含むPOSTなど)、ブラウザはそれをしばらく保持し、それを実行する前に、最初にOPTIONSリクエストをターゲットURLに送信します。上記のように、このOPTIONS要求への応答にCORSヘッダーが含まれている場合にのみ続行します。このOPTIONS呼び出しは、preflight requestとして知られています。
**通常の呼び出しとCORS呼び出しには他にも違いがあるため、almostと言っています。重要なのは、一部のヘッダーは、応答に存在していても、 ヘッダーがAccess-Control-Expose-Headers ヘッダーに含まれていない場合はブラウザーによって取得されないことです。


修正方法

それは単なるタイプミスでしたか? JavaScriptコードは、ターゲットドメインに単なるタイプミスがある場合があります。チェックしましたか?ページがwww.example.comにある場合、www.example.comへの定期的な呼び出しのみを行います! api.example.com、さらにはexample.comwww.example.com:8080などの他のURLは、ブラウザーではdifferentドメインと見なされます!はい、ポートが異なる場合、それは異なるドメインです!

ヘッダーを追加します。 CORSをenableする最も簡単な方法は、サーバーの応答に必要なヘッダー(Access-Control-Allow-Originとして)を追加することです。 (各サーバー/言語にはそれを行う方法があります- ここで解決策を確認してください 。)

ラストリゾート:サービスへのサーバー側アクセスがない場合は、(リバースプロキシなどのツールを使用して)サービスをミラーリングし、インクルードすることもできます。そこに必要なすべてのヘッダー。

163
acdcjunior

あなたのサーバ上でphpが有効になっているならそれをするための一種のハックな方法があります。この行を変更してください。

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

この行に:

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

それからphpスクリプトで(あなたがfile_get_contents()関数を使う許可を持っているなら):

<?php

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

?>

そのURLが別のOriginからのものである場合、Phpは気にしないようです。私が言ったように、これはハックな答えです、そして、それに何か問題があると確信しています、しかしそれは私のために働きます。

編集:あなたがphpで結果をキャッシュしたい場合は、ここであなたが使用するphpファイルです:

<?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;

?>

キャッシングコードは ここ から取得します。

29
jyapayne