JSONPとは何ですか?なぜ作成されたのですか?


2129

JSONは理解していますが、JSONPは理解していません。JSONに関するWikipediaのドキュメントは、(以前は)JSONPの上位の検索結果です。それはこう言います:

JSONPまたは「パディング付きのJSON」は、JSON拡張であり、プレフィックスが呼び出し自体の入力引数として指定されます。

えっ?何といいますか?それは私には意味がありません。JSONはデータ形式です。電話はありません。

第二の検索結果は、名前のいくつかの男からであるレミー JSONPについてはこちらを書き込み、:

JSONPはスクリプトタグインジェクションであり、サーバーからの応答をユーザー指定の関数に渡します。

ある程度は理解できますが、それでもまだ意味がありません。


JSONPとは何ですか?なぜ作成されたのですか(どのような問題を解決しますか)?そして、なぜそれを使うのですか?


補遺:ウィキペディアでJSONPの新しいページを作成しましjvenemaの回答に基づいて、JSONPの明確で完全な説明が追加さました


29
念のため、100%で通信しているサーバーが信頼できない場合はJSONPを使用しないでください。それが侵害された場合、あなたのウェブページは簡単に侵害されます。
ninjagecko 2012年

7
また、JSONP 正しく実装されていないと、ハイジャックされる可能性があることに注意してください。
Pacerier、2015年

3
JSONPの背後にある哲学を提供したJSONPの作者である、JSONP に関するボブ・イッポリトのアーカイブを紹介します。彼はJSONPを「クロスドメインデータフェッチ用のスクリプトタグメソッドの新しいテクノロジーにとらわれない標準的な方法論」として紹介しています。
harshvchawla 2017

回答:


2047

実際にはそれほど複雑ではありません...

あなたがドメインexample.comにいて、ドメインにリクエストをしたいとしますexample.net。これを行うには、次のようにする必要があり、クロスドメインの境界、ノーノー browserlandの大半インチ

この制限を回避する1つのアイテムは<script>タグです。スクリプトタグを使用すると、ドメインの制限は無視されますが、通常の状況では、結果に対して実際に何もできず、スクリプトが評価されるだけです。

と入力しJSONPます。JSONPが有効になっているサーバーにリクエストを送信するときは、サーバーにページについて少し知らせる特別なパラメーターを渡します。このようにして、サーバーはページが処理できる方法で応答をうまくまとめることができます。

たとえば、サーバーcallbackがJSONP機能を有効にするために呼び出されるパラメーターを期待しているとします。次に、リクエストは次のようになります。

http://www.example.net/sample.aspx?callback=mycallback

JSONPがない場合、次のような基本的なJavaScriptオブジェクトが返される可能性があります。

{ foo: 'bar' }

ただし、JSONPを使用すると、サーバーが「callback」パラメーターを受信すると、結果が少し異なり、次のような結果が返されます。

mycallback({ foo: 'bar' });

ご覧のとおり、指定したメソッドが呼び出されます。したがって、ページでコールバック関数を定義します。

mycallback = function(data){
  alert(data.foo);
};

スクリプトが読み込まれると評価され、関数が実行されます。ほら、クロスドメインリクエスト!

また、JSONPの大きな問題の1つに注意する価値があります。それは、リクエストの多くの制御を失うことです。たとえば、適切なエラーコードを返す「素敵な」方法はありません。その結果、タイマーを使用してリクエストなどを監視することになり、常に少し疑わしいものになります。JSONRequestの提案は、クロスドメインスクリプティング、セキュリティの維持、リクエストの適切な制御を可能にする優れたソリューションです。

最近(2015年)、JSONRequest に対してCORSが推奨されるアプローチです。JSONPは古いブラウザーのサポートにも役立ちますが、セキュリティ上の影響があるため、選択肢がない限りCORSの方が適しています。


180
JSONPを使用すると、セキュリティに影響することに注意してください。JSONPは実際にはjavascriptであるため、javascriptが実行できるすべてのことを実行できるため、JSONPデータのプロバイダーを信頼する必要があります。私はそれについてここにsomブログ投稿を書いています:erlend.oftedal.no/blog/?blogid
Erlend

72
<script>タグに存在しないJSONPの新しいセキュリティ上の意味は本当にありますか?スクリプトタグを使用すると、ブラウザーはサーバーを暗黙的に信頼して、ブラウザーが盲目的に評価する無害なJavascriptを配信します。JSONPはその事実を変えますか?それはそうではないようです。
Cheeso

23
いいえ、そうではありません。JavaScriptの配信が信頼できる場合、JSONPにも同じことが当てはまります。
jvenema

15
データの戻り方を変更することで、セキュリティを少し上げることができることは注目に値します。mycallback( '{"foo": "bar"}')などの真のJSON形式でスクリプトを返す場合(パラメーターが文字列になっていることに注意してください)、データを手動で解析して「クリーン」にすることができます。評価しています。
jvenema '15年

8
CURLはサーバー側のソリューションであり、クライアント側ではありません。彼らは2つの異なる目的を果たします。
jvenema

712

JSONPは、XMLHttpRequestの同じドメインポリシーを克服するための本当に簡単なトリックです。(ご存じのとおり、AJAX(XMLHttpRequest)リクエストを別のドメインに送信することはできません。)

そのため、XMLHttpRequestを使用する代わりに、jsが別のドメインからデータを取得するために、jsファイルをロードするために通常使用するスクリプト HTMLタグを使用する必要があります。変な音?

事ですが、スクリプトタグはXMLHttpRequestと同様の方法で使用できることがわかりました。これをチェックしてください:

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data';

データを読み込んだ後、スクリプトセグメントは次のようになります。

<script>
{['some string 1', 'some data', 'whatever data']}
</script>

ただし、スクリプトタグからこの配列をフェッチする必要があるため、これは少し不便です。したがって、JSONPの作成者は、これがより適切に機能することを決定しました(実際はそうです)。

script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data?callback=my_callback';

向こうのmy_callback関数に注目してください。したがって、JSONPサーバーがリクエストを受信して​​コールバックパラメータを見つけると、プレーンなjs配列を返す代わりに、次のように返されます。

my_callback({['some string 1', 'some data', 'whatever data']});

利益がどこにあるかを確認してください。データを取得するとトリガーされる自動コールバック(my_callback)を取得します。JSONP
について知っておくべきことはこれだけです。これは、コールバックとスクリプトタグです。

注:これらはJSONPの使用法の簡単な例であり、本番用のスクリプトではありません。

基本的なJavaScriptの例(JSONPを使用した簡単なTwitterフィード)

<html>
    <head>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
        <script>
        function myCallback(dataWeGotViaJsonp){
            var text = '';
            var len = dataWeGotViaJsonp.length;
            for(var i=0;i<len;i++){
                twitterEntry = dataWeGotViaJsonp[i];
                text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
            }
            document.getElementById('twitterFeed').innerHTML = text;
        }
        </script>
        <script type="text/javascript" src="http://twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script>
    </body>
</html>

基本的なjQueryの例(JSONPを使用した簡単なTwitterフィード)

<html>
    <head>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script>
            $(document).ready(function(){
                $.ajax({
                    url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10',
                    dataType: 'jsonp',
                    success: function(dataWeGotViaJsonp){
                        var text = '';
                        var len = dataWeGotViaJsonp.length;
                        for(var i=0;i<len;i++){
                            twitterEntry = dataWeGotViaJsonp[i];
                            text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
                        }
                        $('#twitterFeed').html(text);
                    }
                });
            })
        </script>
    </head>
    <body>
        <div id = 'twitterFeed'></div>
    </body>
</html>


JSONPJSON with Paddingの略です。(ほとんどの人が「パディング」と考えるものとはまったく関係がないため、非常に不十分な名前のテクニック。)


34
スクリプトタグの説明をありがとう。クロスドメインセキュリティポリシーがJSONPによってどのようにバイパスされているのかを理解できませんでした。説明の後で、私は要点を逃すのが少し愚かだと感じています...
エデュアルド

13
これはjvenemaの回答に対する非常に優れた補足回答です。jsonデータにスクリプト要素を介してアクセスする必要があることを指摘するまで、コールバックが必要な理由を理解できませんでした。
マット

5
そのような明快な説明をありがとう。私の大学の教科書があなたのような人々によって書かれたのを願っています:)
hashbrown '11 / 11/21

1
以前のものよりも良い説明。もちろん、あなたの抜粋「jsが別のドメインからデータを取得するためにjsファイルをロードするために通常使用するもの。奇妙な音ですか?」私にとっても目が開かれます。非常に輝かしいコード例。
SIslam

パディングはリテラルである必要はありません。それは一種の比喩です。したがって、「JSON with some 'spaces'」を意味する場合があります。lol
marvinIsSacul 2018

48

JSONPは、リモートデータサービスの場所にリクエストする「スクリプト」要素(HTMLマークアップまたはJavaScriptを介してDOMに挿入される)を構築することによって機能します。応答は、事前定義された関数の名前と、要求されているJSONデータである渡されたパラメーターがブラウザーにロードされたJavaScriptです。スクリプトが実行されると、JSONデータと共に関数が呼び出され、要求元のページがデータを受信して​​処理できるようになります。

詳細については、 https //blogs.sap.com/2013/07/15/secret-behind-jsonp/をご覧ください。

クライアント側のコードスニペット

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <title>AvLabz - CORS : The Secrets Behind JSONP </title>
     <meta charset="UTF-8" />
    </head>
    <body>
      <input type="text" id="username" placeholder="Enter Your Name"/>
      <button type="submit" onclick="sendRequest()"> Send Request to Server </button>
    <script>
    "use strict";
    //Construct the script tag at Runtime
    function requestServerCall(url) {
      var head = document.head;
      var script = document.createElement("script");

      script.setAttribute("src", url);
      head.appendChild(script);
      head.removeChild(script);
    }

    //Predefined callback function    
    function jsonpCallback(data) {
      alert(data.message); // Response data from the server
    }

    //Reference to the input field
    var username = document.getElementById("username");

    //Send Request to Server
    function sendRequest() {
      // Edit with your Web Service URL
      requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+"");
    }    

  </script>
   </body>
   </html>

サーバー側のPHPコード

<?php
    header("Content-Type: application/javascript");
    $callback = $_GET["callback"];
    $message = $_GET["message"]." you got a response from server yipeee!!!";
    $jsonResponse = "{\"message\":\"" . $message . "\"}";
    echo $callback . "(" . $jsonResponse . ")";
?>

3
たった404秒でトップにあるリンク
Kevin Beal 14年


42

返されたJSONオブジェクトにプレフィックスを付加するようサーバーに要求できるためです。例えば

function_prefix(json_object);

ブラウザがevalJSON文字列を式として「インライン化」するため。このトリックにより、サーバーはクライアントブラウザーにJavaScriptコードを直接「挿入」することが可能になり、これは「同じオリジン」の制限をバイパスします。

つまり、クロスドメインのデータ交換を実現できます。


通常、XMLHttpRequestクロスドメインのデータ交換を直接許可しません(同じドメイン内のサーバーを経由する必要があります)。

<script src="some_other_domain/some_data.js&prefix=function_prefix> `オリジンとは異なるドメインのデータにアクセスできます。


また、注目に値します。そのような「トリック」を試みる前にサーバーを「信頼できる」と見なす必要がある場合でも、オブジェクト形式の変更などの可能性のある副作用を含めることができます。場合function_prefix(すなわち、A、適切なJSが機能)JSONオブジェクトを受信するために使用され、機能がさらに返されたデータを処理する/受け入れる前にチェックを行うことができると述べました。


「接頭辞を追加する」は混乱します:)
jub0bs

19

JSONPは、クロスドメインスクリプティングエラーを回避するのに最適です。サーバー側でAJAXプロキシを実装する必要なく、純粋にJSでJSONPサービスを利用できます。

b1t.coサービスを使用して、その動作を確認できます。これは無料のJSONPサービスで、URLを縮小することができます。サービスに使用するURLは次のとおりです。

http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack]&url=[escapedUrlToMinify]

たとえば、http://b1t.co/Site/api/External/MakeUrlWithGet?callback = whateverJavascriptName&url = google.comの呼び出し

戻るだろう

whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});

したがって、それがsrcとしてjsに読み込まれると、コールバック関数として実装する必要があるJavascriptNameが自動的に実行されます。

function minifyResultsCallBack(data)
{
    document.getElementById("results").innerHTML = JSON.stringify(data);
}

実際にJSONP呼び出しを行うには、いくつかの方法(jQueryの使用を含む)で実行できますが、これは純粋なJSの例です。

function minify(urlToMinify)
{
   url = escape(urlToMinify);
   var s = document.createElement('script');
   s.id = 'dynScript';
   s.type='text/javascript';
   s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
   document.getElementsByTagName('head')[0].appendChild(s);
}

ステップバイステップの例と実践するためのjsonp Webサービスは、こちらの投稿で入手できます。


2
回答を投稿していただきありがとうございます。回答の本質的な部分をこのサイトに投稿する必要があります。そうしないと、投稿が削除されるリスクがあります。「リンクよりもかろうじて」回答について言及しているFAQを参照してください。必要に応じてリンクを含めることもできますが、これは「参照」としてのみです。答えはリンクを必要とせず、それ自体で成り立つべきです。
タリン

14

JSONPの簡単な使用例。

client.html

    <html>
    <head>
   </head>
     body>


    <input type="button" id="001" onclick=gO("getCompany") value="Company"  />
    <input type="button" id="002" onclick=gO("getPosition") value="Position"/>
    <h3>
    <div id="101">

    </div>
    </h3>

    <script type="text/javascript">

    var elem=document.getElementById("101");

    function gO(callback){

    script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://localhost/test/server.php?callback='+callback;
    elem.appendChild(script);
    elem.removeChild(script);


    }

    function getCompany(data){

    var message="The company you work for is "+data.company +"<img src='"+data.image+"'/   >";
    elem.innerHTML=message;
}

    function getPosition(data){
    var message="The position you are offered is "+data.position;
    elem.innerHTML=message;
    }
    </script>
    </body>
    </html>

server.php

  <?php

    $callback=$_GET["callback"];
    echo $callback;

    if($callback=='getCompany')
    $response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";

    else
    $response="({\"position\":\"Development Intern\"})";
    echo $response;

    ?>    

8

JSONPを理解する前に、JSON形式とXMLを理解する必要があります。現在Webで最も頻繁に使用されているデータ形式はXMLですが、XMLは非常に複雑です。これにより、ユーザーはWebページに埋め込まれた処理が不便になります。

JavaScriptがデータを簡単に交換できるようにするために、データ処理プログラムとしても、JavaScriptオブジェクトに従って表現を使用し、JSONである単純なデータ交換フォーマットを開発しました。JSONはデータとして、またはJavaScriptプログラムとして使用できます。

JSONはJavaScriptに直接埋め込むことができ、それらを使用して特定のJSONプログラムを直接実行できますが、セキュリティ上の制約により、ブラウザーのサンドボックスメカニズムはクロスドメインJSONコードの実行を無効にします。

実行後にJSONを渡せるようにするために、JSONPを開発しました。JSONPは、JavaScriptコールバック機能と<script>タグを使用して、ブラウザーのセキュリティ制限を回避します。

つまり、JSONPとは何か、それが解決する問題(いつ使用するか)について説明します。


4
私がこれに反対したのは、XMLがWebで最も使用されているdat形式であるという声明が、2015年12月に信じられないためです。
RobbyD 2017年

それでも、jsonの代わりにjsonpが使用される理由はわかりません。これらのセキュリティ制限はどこから来ているのですか?クロスドメインにjsonpを使用できるのにjsonを使用できないのはなぜですか?
Merunas Grincalaitis

6

TL; DR

JSONPは、別のサーバー(別のオリジン*)からJSONデータを取得することを禁止するセキュリティ制限を回避するために考案された古いトリックです。

トリックは<script>、その場所からJSONを要求するタグを使用することで{ "user":"Smith" }機能します。例:が、実際のJSONP(「JSON with Padding」)の関数にラップされています。

peopleDataJSONP({"user":"Smith"})

この形式で受信すると、peopleDataJSONP関数内でデータを使用できます。JSONPは悪い習慣です。使用しないでください(以下をお読みください)


問題

ナビゲートしていてourweb.com、JSONデータ(または実際の生データ)をから取得したいとしますanotherweb.com。GETリクエスト(XMLHttpRequestfetch呼び出し$.ajaxなど)を使用する場合、ブラウザはこの醜いエラーで許可されていないことを通知します。

Chrome CORSコンソールエラー

必要なデータを取得するにはどうすればよいですか?まあ、<script>タグはこのサーバー全体(origin *)の制限を受けません!そのため、jQueryやGoogleマップなどのライブラリをCDNなどの任意のサーバーからエラーなしでロードできます。

重要なポイント:考えてみれば、これらのライブラリは実際の実行可能なJSコード(通常、すべてのロジックが内部にある大規模な関数)です。しかし生データ?JSONデータはコードではありません。実行するものは何もありません。単なるデータです。

したがって、貴重なデータを処理または操作する方法はありません。ブラウザは<script>タグが指すデータをダウンロードし、処理する際に当然のように文句を言うでしょう:

{"user":"Smith"}我々がロードしたこのがらくたはwtf ですか?コードではありません。計算できません、構文エラーです!


JSONPハック

そのデータを利用する古い/ハッキーな方法?何らかのロジックを使用してサーバーに送信する必要があるので、サーバーが読み込まれると、ブラウザーのコードでこのデータを使用できるようになります。したがって、外部サーバーはJS関数内でJSONデータを送信します。データ自体は、その関数の入力として設定されます。次のようになります。

peopleDataJSONP({"user":"Smith"})

これにより、ブラウザが文句なしに解析できるJSコードになります。jQueryライブラリの場合とまったく同じです。これを実現するために、クライアントはJSONP対応のサーバーに「要求」します。通常は次のようにします。

<script src="https://anotherweb.com/api/data-from-people.json?myCallback=peopleDataJSONP"></script>

私たちのブラウザーはその関数名を持つJSONPを受け取るので、次のように、コード内に同じ名前の関数が必要です。

const peopleDataJSONP = function(data){
  alert(data.user); // "Smith"
}

またはこのように、同じ結果:

function peopleDataJSONP(data){
  alert(data.user); // "Smith"
}

ブラウザはJSONPをダウンロードして実行し、関数を呼び出しdataます。ここで、引数はJSONです。これで、データを好きなように処理できます。


JSONPを使用せず、CORSを使用

JSONPは、いくつかの欠点があるクロスサイトハックです。

  • GETリクエストのみ実行できます
  • これは単純なスクリプトタグによってトリガーされるGETリクエストであるため、有用なエラーや進捗情報は取得されません
  • 悪意のあるペイロードに変更される可能性のあるクライアントJSコードでの実行など、いくつかのセキュリティ上の懸念もあります
  • JSONデータの問題のみを解決しますが、Same-Originセキュリティポリシーは他のデータ(WebFonts、drawImage()で描画された画像/ビデオ)に適用されます
  • それは非常にエレガントでも可読でもありません。

要点は、最近は使用する必要がないことです。

JSONPは別のサーバーからJSONデータを取得するトリックですが、他の種類のクロスサイトのものが必要な場合は、同じセキュリティ原則(Same-Origin)に違反します。

ここCORSについて読む必要がありますが、その要点は次のとおりです。

クロスオリジンリソースシェアリング(CORS)は、追加のHTTPヘッダーを使用して、あるオリジンで実行されているWebアプリケーションに、別のオリジンから選択されたリソースへのアクセスを許可するようにブラウザーに指示するメカニズムです。Webアプリケーションは、独自のオリジン(ドメイン、プロトコル、またはポート)を持つリソースを要求すると、クロスオリジンHTTP要求を実行します。



* originは、プロトコルポートホストの 3つの要素で定義されます。したがって、たとえば、(異なるプロトコル)および(異なるポート)とは明らかにhttps://web.com異なる起源であり、明らかに(異なるホスト)http://web.comhttps://web.com:8081https://thatotherweb.net


1
おいおい、これは承認された答えへの脚注として100%の明快さを提供した!これをありがとう....
M'Baku

4

すばらしい答えはすでに出ています。JavaScriptのコードブロックの形式で自分の作品を提供する必要があるだけです(クロスオリジンリクエストのよりモダンで優れたソリューション:HTTPヘッダー付きCORSも含めます):

JSONP:

1.client_jsonp.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/?callback=?",
    dataType: "jsonp",
    success: function(data) {
        console.log(data);    
    }
});​​​​​​​​​​​​​​​​​​

2.server_jsonp.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {

    var callback = url.parse(req.url, true).query.callback || "myCallback";
    console.log(url.parse(req.url, true).query.callback);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    data = callback + '(' + JSON.stringify(data) + ');';

    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(data);
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);

CORS

3.client_cors.js

$.ajax({
    url: "http://api_test_server.proudlygeek.c9.io/",
    success: function(data) {
        console.log(data);    
    }
});​

4.server_cors.js

var http = require("http"),
    url  = require("url");

var server = http.createServer(function(req, res) {
    console.log(req.headers);

    var data = {
        'name': "Gianpiero",
        'last': "Fiorelli",
        'age': 37
    };

    res.writeHead(200, {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*'
    });

    res.end(JSON.stringify(data));
});

server.listen(process.env.PORT, process.env.IP);

console.log('Server running at '  + process.env.PORT + ':' + process.env.IP);

1

JSONPJSON with Paddingの略です。

ここでのサイト、ある偉大な例最も簡単な使用からの説明と、この技術の最も進んに平面JavaScriptでは:

w3schools.com / JSONP

上記で説明した私のお気に入りのテクニックの1つは動的JSON結果です。これにより、JSONをURLパラメータPHPファイルに送信し、取得した情報に基づいPHPファイルにもJSONオブジェクトを返すことができます。

jQueryのようなツールには、JSONPを使用する機能もあります

jQuery.ajax({
  url: "https://data.acgov.org/resource/k9se-aps6.json?city=Berkeley",
  jsonp: "callbackName",
  dataType: "jsonp"
}).done(
  response => console.log(response)
);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.