web-dev-qa-db-ja.com

JSONPとは何か、素人用語で説明できる人はいますか。

JSONPはパディング付きのJSONです。

JSONとは何か、そしてそれを jQuery.getJSON() と一緒に使用する方法を理解しています。しかし、JSONPを導入するとき、私はcallbackの概念を理解していません。

これがどのように機能するかを誰かが私に説明できますか?

408
Someone

序文:

この答えは6歳以上です。 JSONPの概念とアプリケーションは変わっていませんが(つまり答えの詳細はまだ有効です)、 可能であればCORSを使うようにしてください (つまりあなたの server またはJSONPとして、 API がサポートされています。 ブラウザサポート で十分です) 固有のセキュリティリスクがあります


JSONP(JSON with Padding)は、Webブラウザでクロスドメインポリシーを回避するために一般的に使用されている方法です。 (ブラウザによって異なるサーバー上にあると認識されているWebページへのAJAX要求を行うことは許可されていません。)

JSONとJSONPは、クライアントとサーバーで動作が異なります。 JSONPリクエストはXMLHTTPRequestおよび関連するブラウザメソッドを使ってディスパッチされることはありません。代わりに、ソースがターゲットURLに設定されている<script>タグが作成されます。その後、このスクリプトタグがDOMに追加されます(通常は<head>要素内)。

JSONリクエスト:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    // success
  };
};

xhr.open("GET", "somewhere.php", true);
xhr.send();

JSONPリクエスト:

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);

JSONレスポンスとJSONPレスポンスの違いは、JSONPレスポンスオブジェクトは引数としてコールバック関数に渡されることです。

JSON:

{ "bar": "baz" }

JSONP:

foo( { "bar": "baz" } );

これが、JSONPリクエストにcallbackパラメータが含まれていることを示しているためです。これにより、サーバーはレスポンスをラップする関数の名前を知ることができます。

この関数は、グローバルスコープに存在している必要があります<script>タグはブラウザによって評価されます(要求が完了した後)。


JSON応答の処理とJSONP応答の処理の間で注意すべきもう1つの違いは、JSON応答の解析エラーがtry/catchステートメントでresponseTextを評価する試みをラップすることによって検出される可能性があることです。 JSONPレスポンスの性質上、レスポンス内の解析エラーにより、キャッチできないJavaScript解析エラーが発生します。

どちらの形式でも、要求を開始する前にタイムアウトを設定し、応答ハンドラでタイムアウトをクリアすることによってタイムアウトエラーを実装できます。


JSONPリクエストを行うためにjQueryを使用することの有用性は、jQueryがバックグラウンドですべての作業を行うことです。

デフォルトでjQueryはあなたのAJAXリクエストのURLに&callback=?を含めることを要求します。 jQueryはあなたが指定したsuccess関数を取り、それにユニークな名前を割り当て、そしてグローバルスコープでそれを公開します。それはそれからそれが割り当てた名前で?の疑問符&callback=?を置き換えます。


同等のJSON/JSONP実装

以下はレスポンスオブジェクト{ "bar" : "baz" }を仮定しています

JSON:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
  };
};

xhr.open("GET", "somewhere.php", true);
xhr.send();

JSONP:

function foo(response) {
  document.getElementById("output").innerHTML = response.bar;
};

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);
761
Matt

次のようなJSONデータを提供するURLがあるとします。

{'field': 'value'}

...そして、あなたがコールバック関数名 'myCallback'を渡したJSONPを使用することを除いて同様のURLを持っていました(通常 'callback'と呼ばれるクエリパラメータを与えることによって行われます、例えばhttp://example.com/dataSource?callback=myCallback)それからそれは戻ります:

myCallback({'field':'value'})

...これは単なるオブジェクトではありませんが、実際には実行可能なコードです。そのため、ページの他の場所でmyFunctionという関数を定義してこのスクリプトを実行すると、URLからのデータを使用して呼び出されます。

これについての素晴らしいことは、スクリプトタグを作成し、あなたのURL(callbackパラメータを付けて)をsrc属性として使うことができ、ブラウザがそれを実行することです。つまり、ブラウザではページのドメイン以外のソースからスクリプトタグを実行できるため、 'same-Origin'セキュリティポリシーを回避できます。

これがあなたがajaxリクエストをするときにjQueryがすることです(dataTypeプロパティの値として 'jsonp'と共に .ajax を使う)。例えば。

$.ajax({
  url: 'http://example.com/datasource',
  dataType: 'jsonp',
  success: function(data) {
    // your code to handle data here
  }
});

ここでは、jQueryがコールバック関数名とクエリパラメータを処理し、APIを他のajax呼び出しと同じにします。しかし、他の種類のajaxリクエストとは異なり、前述のように、あなたはあなたのページと同じOriginからデータを取得することに制限されていません。

73
sje397

JSONPはブラウザの 同一Originポリシー を回避する方法です。どうやって?このような:

enter image description here

ここでの目標は、応答の中の名前にotherdomain.comalertを要求することです。通常はAJAXリクエストを行います。

$.get('otherdomain.com', function (response) {
  var name = response.name;
  alert(name);
});

ただし、要求は別のドメインに送信されるため、機能しません。

<script>タグを使ってリクエストを行うこともできます。 <script src="otherdomain.com"></script>$.get('otherdomain.com')の両方が同じリクエストを行います。

GET otherdomain.com

Q:しかし<script>タグを使用した場合、どうやってアクセスできますか? alertにしたい場合は、アクセスする必要があります。

A:ええと、できません。しかし、これが可能なことです - レスポンスを使用する関数を定義してから、レスポンスを引数として関数を呼び出すJavaScriptで応答するようにサーバーに指示します。

Q:しかし、もしサーバーが私たちのためにこれをしないで、そして私たちにJSONを返すことを喜んでだけ行うならばどうでしょうか?

A:それならそれを使うことはできません。 JSONPは協力することをサーバに要求します。

Q:<script>タグを使わなければならないのは醜いです。

A:jQueryのようなライブラリ より良くする 。例:

$.ajax({
    url: "http://otherdomain.com",
    jsonp: "callback",
    dataType: "jsonp",
    success: function( response ) {
        console.log( response );
    }
});

動的に<script>タグのDOM要素を作成することによって機能します。

Q:<script>タグはGETリクエストのみを行います - POSTリクエストをしたい場合はどうしますか?

A:それならJSONPは私達のために働きません。

Q:大丈夫です、GETリクエストをしたいだけです。 JSONPはすごいです、そして私はそれを使いに行くつもりです - ありがとう!

A:実際、それほど素晴らしいことではありません。それは本当に単なるハックです。そしてそれは 最も安全ではない 使うべきこと。 CORSが利用可能になったので、可能ならいつでもそれを使うべきです。

17
Adam Zerner

私はまた、そのトピックを非常に明確かつ簡単に説明している便利な記事を見つけました。リンクは JSONP

注目に値する点は次のとおりです。

  1. JSONPはCORSよりも前の日付です。
  2. 異なるドメインからデータを取得するための疑似標準的な方法です。
  3. CORS機能には制限があります(GETメソッドのみ)。

作業は次のとおりです。

  1. <script src="url?callback=function_name">はhtmlコードに含まれています
  2. ステップ1が実行されると、応答として同じ関数名(urlパラメータで指定されたもの)を持つ関数が検出されます。
  3. 指定された名前の関数がコード内に存在する場合、その関数への引数として返されたデータがあればそれが実行されます。
2
Harshit Garg