9

私が制御していない REST サービスにアクセスしようとしています。最初の問題は、サービスに Access-Control-Allow-Origin ヘッダーが含まれていないことです。これは、私が正しく理解している場合、すぐに JSONP に制限される問題です。

また、デフォルトでは、このサービスは JSON を送信できますが、JSON ではなく XML を送信します。私の Accept ヘッダーに応答する必要があると思います。サービスの責任者は、私の Content-Type を見ていると言っています。これは、GET ではなく POST を実行する必要があることを意味します (ただし、静的データを取得するだけの場合は get の方が理にかなっていますよね?)。

私は頑固なので、最初に Accept ヘッダーを試しています。Angular は JSON のみを受け入れるため、デフォルトでヘッダーを使用することを期待しAccept: application/jsonますが、そうではなく、手動で設定しようとしても無視されます。

app.config(['$httpProvider', function($httpProvider){
    console.log($httpProvider.defaults.headers.common);
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
    $httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript';
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
    $httpProvider.defaults.headers.post['Access-Control-Max-Age'] = '1728000';
    $httpProvider.defaults.headers.common['Access-Control-Max-Age'] = '1728000';
    $httpProvider.defaults.headers.common['Accept'] = 'application/json, text/javascript';
    $httpProvider.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
    $httpProvider.defaults.useXDomain = true;
}]);

実際のリソースでこれをもう一度行います。

return $resource('http://foo.com/getStuff', {}, {
    fetch: {
        method:'JSONP',
        params: params,
        headers: {
            'Accept':'application/json, text/javascript',
            'Content-Type':'application/json; charset=utf-8'
        },
        isArray:false,
        callback: 'JSON_CALLBACK'
    }
});

それでも、リクエスト ヘッダーにはAccept: */*.

私の質問は:なぜですか?Angular がヘッダーを無視するのはなぜですか? とにかく、適切なヘッダーを使用するにはどうすればよいですか?

また、POSTでJSONPを使用する方法はありますか?

編集:もともとAngular 1.0.7を使用していましたが、1.2.3で試してみたところ、同じ結果が得られました。ヘッダーは無視されますが、誰もがこれがその方法だと主張しています。

また、$resource ではなく、$http で直接実行しようとしましたが、同じ結果になりました。

編集 2:ここにJSFiddleがあります。匿名化されており、実サーバーは使用していませんが、Firebug/開発者ツールを使用すると、ヘッダーAccept: */*を設定しようと何度も試みたにもかかわらず、両方の呼び出しで送信されることを確認できます。application/jsonそして、それが私の本当の問題です。私の実サーバーでは、実サーバーが JSON を送信できるにもかかわらず、XML の結果を取得しています。

(実際のサーバーが jsonp をサポートしているかどうかは、現時点ではそれほど重要ではありません。このダミー サーバーは明らかにサポートしていませんが、問題ありません。私はヘッダーが気になるだけです。)

編集3:以下に提案されている両方のソリューションを試しました:

$http.defaults.headers.common['Accept'] = 'application/json, text/javascript';

$http.defaults.transformRequest.push(function (data, headersGetter) {
    headersGetter().Accept = "application/json, text/javascript";
    return data;
});

私は両方のステートメントを別々に試しました。コントローラーで、次に http 呼び出し自体の直前のサービスで。それでもうまくいきません。

これが機能することが示されているJsFiddleを誰かに教えてもらえますか?

編集 4: JSONP ではなく GET を使用すると、Accept ヘッダーが正しいことに気付きました。しかし、正しいヘッダーがないため、応答は拒否されます。

JSONP 呼び出しにはどのような種類のヘッダーが必要ですか? JSONP 呼び出しにはさらに多くのヘッダーがありますが、それを JSONP として識別するものは何もないためです。これを機能させるには、サーバーが明示的な JSONP サポートを持っている必要がありますか? 私はjsonpについてほとんど知らないことに突然気づきました。

4

3 に答える 3

12

あなたの答えはここにあると思います。wikiによると、 JSONP 呼び出しは、<script>タグを挿入して実行され、ホスト サーバーからスクリプトをロードします。ホスト サーバーは、コールバックを呼び出して応答し、データを渡します。<script>タグは通常のブラウザー リクエスト ( ではなく) を生成し、XmlHttpRequestブラウザーは独自の Accept ヘッダーを送信します (たとえば、独自の User-Agent ヘッダーも送信します)。

これを行うためのより簡単なクライアント側の方法があることを願っていますが、唯一の方法は、参照された投稿で提案されている方法である可能性があると思います:

したがって、クロスドメイン呼び出しのリクエストヘッダーを設定できるようにする場合は、ドメインにサーバー側スクリプトをセットアップして、リモートドメインに呼び出しを委任し (およびそれぞれのヘッダーを設定し)、AJAX 要求を送信する必要があります。あなたのスクリプトに。

編集:これは、この同じ問題に関する (拒否された) jQuery バグ レポートです。

その他の背景情報:

angularでは、コールバックは自動的に管理されるため、次のように言うと:

$http({
    method: "JSONP",
    url: "http://headers.jsontest.com?callback=JSON_CALLBACK",
}).success(function(data) {
    console.log('Return value:');
    console.log(data);
}).error(function(data) {
    console.log('Error!');
    console.log(data);
})

<script>多かれ少なかれ次のようなタグが作成されます。

<script type="application/javascript"
        src="http://headers.jsontest.com/?callback=angular.callbacks._1">
</script>

への応答の内容は次のようにhttp://headers.jsontest.com/?callback=angular.callbacks._1なります。

angular.callbacks._1({key1: "value1", key2: "value2"});

angular.callbacks._1関数が含まれsuccess、データで呼び出されます。

于 2013-12-05T15:53:11.517 に答える
0

あなたが持っているものはドキュメントに従って動作するはずですが、私の経験は少し異なります. この問題を回避するために、次のことを行いました。

ページの body タグまたは html タグに追加される「ベース コントローラ」を作成します。そのコントローラーで、$httpProvider の代わりに $http を使用して割り当てを行います。ベース コントローラーは最初のページが読み込まれるときに読み込まれるため、アプリで実行される他のすべてのコントローラーとサービスのために存在します。

なぜこれが機能し、禁止された方法が機能しないのかはわかりません。この回避策よりも優れた質問への回答をお待ちしておりますが、少なくともこれにより、開発を再び進めることができます。

于 2013-12-04T15:12:41.950 に答える
0

以下は私にとってはうまくいきます-しかし、私は「実行時」にそれを行い、ブートストラップ中$httpには使用していません$httpProvider

function SomeCtrl($http) {

    $http.defaults.transformRequest.push(function (data, headersGetter) {
        headersGetter().Accept = "application/json, text/javascript";
        return data;
    });

}

編集

これは動作中のjsFiddleバージョンです。Developer Tools/Firebug で行われたリクエストを確認し、リクエストされていることを確認し"application/json, text/javascript"ます。

于 2013-12-04T16:27:21.410 に答える