web-dev-qa-db-ja.com

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

私はJSONを理解していますが、JSONPは理解していません。 JSONに関するウィキペディアの文書 はJSONPのトップの検索結果です。それはこう言います:

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

え?何の電話?それは私には意味がありません。 JSONはデータフォーマットです。電話はありません。

2番目の検索結果 は、JSONPについて次のように書いている Remy という名前の人からのものです。

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

私はある種のことを理解することができますが、それでも意味がありません。


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


補遺 :私は JSONP用の新しいページを作成しました - ウィキペディアに; jvenema の答えに基づいて、JSONPの明確で徹底的な説明が追加されました。

1955
Cheeso

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

Example.comというドメインに所属していて、example.netというドメインにリクエストを送信したいとします。そのためには、ドメインの境界を越える必要があります。これは、ほとんどのブラウザランドでは不可能です。

この制限を回避する1つの項目は<script>タグです。 scriptタグを使用すると、ドメインの制限は無視されますが、通常の状況下では、結果に do 何かを指定することはできません。スクリプトは評価されるだけです。

JSONPを入力してください。 JSONPが有効になっているサーバーにリクエストを送信するときは、ページについて少しサーバーに通知する特別なパラメーターを渡します。そうすれば、サーバーはあなたのページが扱えるようにそのレスポンスをうまくまとめることができます。

たとえば、サーバーがJSONP機能を有効にするために "callback"というパラメータを必要としているとします。それならあなたの要求は次のようになります。

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年)、 _ cors _ がJSONRequestに対する推奨アプローチです。 JSONPは古いブラウザのサポートにはまだ便利ですが、セキュリティ上の意味から、CORSがより良い選択である場合を除きます。

1903
jvenema

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

つまり、 XMLHttpRequest の代わりに、 script HTMLタグを使用する必要があります。これは、jsが別のドメインからデータを取得するために、通常はjsファイルをロードするために使用します。変に聞こえますか?

つまり、 script タグは XMLHttpRequest !のように使用できます。これをチェックしてください。

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

データをロードした後は、 script セグメントのようになります。

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

しかし、これは少し不便です。なぜなら、この配列を script tagから取得する必要があるからです。だから _ jsonp _ クリエイターはこれがよりうまくいくと決めました(そしてそれはそうです):

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

向こうに my_callback 関数がありますか?つまり、 _ jsonp _ serverがリクエストを受信して​​コールバックパラメータを見つけた場合 - プレーンな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>


_ jsonp _ は、 JSONとPadding を表します。 (ほとんどの人が「パディング」と考えるものとはまったく関係ないので、非常に貧弱な名前の付けられた技法。)

674
ThatGuy

JSONPは、(HTMLマークアップで、またはJavaScriptを介してDOMに挿入された)「script」要素を構築することによって機能します。これは、リモートデータサービスの場所に要求します。レスポンスは、事前に定義された関数の名前と、リクエストされている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 code

<?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 . ")";
?>
43
Ajain Vivek

返されたJSONオブジェクトにプレフィックスを追加するようにサーバーに依頼できるからです。例えば

function_prefix(json_object);

ブラウザがeval "式"としてJSON文字列を "インライン"にするため。このトリックにより、サーバーはクライアントブラウザに直接JavaScriptコードを「挿入」することができます。これは、「同じOrigin」の制限を回避して行うことができます。

言い換えれば、 クロスドメインデータ交換 を持つことができます。


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

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


同様に注目に値する:たとえその種の「トリック」を試みる前にサーバが「信頼されている」と見なされるべきであっても、オブジェクトフォーマットの変更などの可能性のある副作用が含まれる可能性があります。 function_prefix(すなわち、適切なjs関数)がJSONオブジェクトを受け取るために使用される場合、前記関数は、返されたデータを受け入れる/さらに処理する前にチェックを実行できます。

38
jldupont

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にロードされると、自動的にコールバック関数として実装すべきwhateverJavascriptNameを実行します。

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サービスは次の場所にあります。 この記事

18
dardawk

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;

    ?>    
12
sarath joseph

JSONPを理解する前に、JSONフォーマットとXMLについて知っておく必要があります。現在Web上で最も頻繁に使用されているデータ形式はXMLですが、XMLは非常に複雑です。これは、Webページに埋め込まれた処理をユーザーにとって不便にします。

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

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

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

つまり、JSONPとは何か、それがどのような問題を解決するのか(いつ使用するのか)について簡単に説明します。

10
Marcus Thornton

素晴らしい答えがすでに与えられています、私はちょうど私の作品を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);
3
Humoyun