JQueryなしでJavaScriptからJSONPリクエストを行う方法は?


122

jQueryやその他の外部ライブラリを使用せずに、JavaScriptでクロスドメインJSONPリクエストを作成できますか?JavaScript自体を使用してから、データを解析してオブジェクトにして、使用できるようにしたいと考えています。外部ライブラリを使用する必要がありますか?そうでない場合、どうすればよいですか?


回答:


151
function foo(data)
{
    // do stuff with JSON
}

var script = document.createElement('script');
script.src = '//example.com/path/to/jsonp?callback=foo'

document.getElementsByTagName('head')[0].appendChild(script);
// or document.head.appendChild(script) in modern browsers

2
WikipediaのJSONPいじるのに使用できるJSBinがあります。この回答で参照されました
rkagerer 2013年

1
応答が次の形式であることを指摘する価値があると思います:foo(payload_of_json_data)スクリプトタグに読み込まれると、javascriptオブジェクトとしてのペイロードを使用してfoo関数を呼び出し、解析は不要です。
タコ

@WillMunn JSONPでそれができるとは思いません。CORS以前の時代のハックです。ヘッダーを設定するために何が必要ですか?サーバーは特にJSONPリクエストを受け入れる必要があるため、正常に機能するように設定する必要があります。
マットボール

あなたは正しい、私はいくつかのAPIドキュメントを読み間違えました、jsonp appologiesを使用するときに私が望んだことをするための特別なクエリパラメーターがあります。
Will Munnは

@WillMunn心配ありません。それを整理することができてうれしい!
マットボール

37

軽量の例(onSuccessおよびonTimeoutのサポートあり)。必要な場合は、URL内でコールバック名を渡す必要があります。

var $jsonp = (function(){
  var that = {};

  that.send = function(src, options) {
    var callback_name = options.callbackName || 'callback',
      on_success = options.onSuccess || function(){},
      on_timeout = options.onTimeout || function(){},
      timeout = options.timeout || 10; // sec

    var timeout_trigger = window.setTimeout(function(){
      window[callback_name] = function(){};
      on_timeout();
    }, timeout * 1000);

    window[callback_name] = function(data){
      window.clearTimeout(timeout_trigger);
      on_success(data);
    }

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
    script.src = src;

    document.getElementsByTagName('head')[0].appendChild(script);
  }

  return that;
})();

使用例:

$jsonp.send('some_url?callback=handleStuff', {
    callbackName: 'handleStuff',
    onSuccess: function(json){
        console.log('success!', json);
    },
    onTimeout: function(){
        console.log('timeout!');
    },
    timeout: 5
});

GitHubで:https : //github.com/sobstel/jsonp.js/blob/master/jsonp.js


29

JSONPとは何ですか?

jsonpで覚えておくべき重要なことは、jsonpは実際にはプロトコルやデータ型ではないということです。その場でスクリプトをロードし、ページに導入されたスクリプトを処理するための単なる方法です。JSONPの精神では、これはサーバーからクライアントアプリケーション/スクリプトに新しいJavaScriptオブジェクトを導入することを意味します。

JSONPはいつ必要ですか?

これは、1つのドメインが同じページ内の別のドメインに非同期でデータにアクセス/処理できるようにする1つの方法です。主に、XHR(ajax)リクエストで発生するCORS(Cross Origin Resource Sharing)制限を無効にするために使用されます。スクリプトの読み込みはCORSの制限の対象ではありません。

どうやって

サーバーからの新しいJavaScriptオブジェクトの導入はさまざまな方法で実装できますが、最も一般的な方法は、サーバーが必要なオブジェクトを渡して「コールバック」関数の実行を実装することです。コールバック関数は、クライアントに既に設定されている関数であり、スクリプトがロードされた時点でロードされたスクリプトが呼び出して、渡されたデータを処理します。

例:

誰かの家にあるすべてのアイテムをログに記録するアプリケーションがあります。アプリケーションが設定され、メインベッドルームのすべてのアイテムを取得したいと思います。

私のアプリケーションはオンapp.home.comです。データのロードに必要なAPIはオンapi.home.comです。

サーバーがそれを許可するように明示的に設定されていない限り、ajaxを使用してこのデータをロードすることはできません。別個のサブドメインのページでさえ、XHR CORSの制約を受けるためです。

理想的には、xドメインXHRを許可するように設定します

理想的には、APIとアプリが同じドメインにあるので、にヘッダーを設定するためのアクセス権があるかもしれませんapi.home.com。その場合は、Access-Control-Allow-Origin: へのアクセスを許可するヘッダーアイテムを追加できますapp.home.com。ヘッダーが次のように設定されているとすると、Access-Control-Allow-Origin: "http://app.home.com"JSONPを設定するよりもはるかに安全です。これは、CORSにインターネット全体へのアクセスを許可しなくても、app.home.com必要なものすべてを取得できるためです。api.home.comapi.home.com

上記のXHRソリューションは不可能です。JSONPを設定するクライアントスクリプト:JSONP呼び出し を行うときにサーバーからの応答を処理する関数を設定します。

function processJSONPResponse(data) {
    var dataFromServer = data;
}

サーバーは次のようなものを探してミニスクリプトを返すように設定する必要があります"processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"のようなものがあれば、このような文字列を返すように設計されるかもしれない//api.home.com?getdata=room&room=main_bedroomと呼ばれています。

次に、クライアントは次のようにスクリプトタグを設定します。

var script = document.createElement('script');
script.src = '//api.home.com?getdata=room&room=main_bedroom';

document.querySelector('head').appendChild(script);

これにより、スクリプトが読み込まwindow.processJSONPResponse()れ、サーバーによって書き込まれた/エコー/印刷されたとおりにすぐに呼び出されます。関数へのパラメーターとして渡されたデータはdataFromServerローカル変数に格納され、必要に応じてそれを使用できます。

掃除

クライアントがデータを取得すると、スクリプトがDOMに追加された直後に、script要素をDOMから削除できます。

script.parentNode.removeChild(script);

2
おかげで、これは私のプロジェクトで非常に役立ちました。小さな問題:が届きましたSyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data。データに単一引用符を追加した後、すべてがそう、罰金を働いた:"processJSONPResponse('{"room":"main bedroom","items":["bed","chest of drawers"]}');"
ハインヴァンダイク

17

私の理解では、実際にはJSONPでスクリプトタグを使用しています。

最初のステップは、JSONを処理する関数を作成することです。

function hooray(json) {
    // dealin wit teh jsonz
}

この関数がグローバルレベルでアクセス可能であることを確認してください。

次に、DOMにスクリプト要素を追加します。

var script = document.createElement('script');
script.src = 'http://domain.com/?function=hooray';
document.body.appendChild(script);

スクリプトは、APIプロバイダーが作成したJavaScriptをロードして実行します。


2
みんな、ありがとう。いくつかのデータを検索するためにインターネット上で発砲し、それを使って何かをしました。私はオブジェクトを処理するのに役立つ応答データでeval()を使用しました-それがそうである配列です(私は思います)。{それは私の限られた頭脳力で構文解析を理解しているクマでしたが、私はついにそれから値を引き出しました}。素晴らしい。
Dave、

@Dave @Mattたぶん私 JSONPでぼんやりしているかもしれませんがeval、必要ないはずparseです。ブラウザが実行できるJavaScriptを取得する必要がありますよね?
sdleihssirhc '26年

ご迷惑をおかけして申し訳ありません。配列からthing(value?property?)を取得しようとすると、頭が回転しました(ネスト、コールバック、配列、要素、オブジェクト、文字列、値、中括弧、角括弧...)。evalの使用を削除しても、必要な配列(object?element?)からproperty(value?)を取得しました。
デイブ

10

以下のようにjsonpを使用する方法:

function jsonp(uri) {
    return new Promise(function(resolve, reject) {
        var id = '_' + Math.round(10000 * Math.random());
        var callbackName = 'jsonp_callback_' + id;
        window[callbackName] = function(data) {
            delete window[callbackName];
            var ele = document.getElementById(id);
            ele.parentNode.removeChild(ele);
            resolve(data);
        }

        var src = uri + '&callback=' + callbackName;
        var script = document.createElement('script');
        script.src = src;
        script.id = id;
        script.addEventListener('error', reject);
        (document.getElementsByTagName('head')[0] || document.body || document.documentElement).appendChild(script)
    });
}

次に、次のような「jsonp」メソッドを使用します。

jsonp('http://xxx/cors').then(function(data){
    console.log(data);
});

参照:

JsonPを使用したJavaScript XMLHttpRequest

http://www.w3ctech.com/topic/721(Promiseの使用方法について話す)


1
割り当てを終了します。script.src= src; 「;」を追加 すべての割り当ての最後まで
chdev77

6

私はそれを行うための純粋なjavascriptライブラリを持っていますhttps://github.com/robertodecurnex/J50Npi/blob/master/J50Npi.js

それを見て、コードの使用または理解について助けが必要な場合は私に知らせてください。

ところで、ここに簡単な使用例があります:http : //robertodecurnex.github.com/J50Npi/


6
あなたのソリューションは私のユースケースには少し単純過ぎたので、複数のリクエストのサポートを追加しましたgist.github.com/1431613
Chad

5
/**
 * Loads data asynchronously via JSONP.
 */
const load = (() => {
  let index = 0;
  const timeout = 5000;

  return url => new Promise((resolve, reject) => {
    const callback = '__callback' + index++;
    const timeoutID = window.setTimeout(() => {
      reject(new Error('Request timeout.'));
    }, timeout);

    window[callback] = response => {
      window.clearTimeout(timeoutID);
      resolve(response.data);
    };

    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
    script.src = url + (url.indexOf('?') === -1 ? '?' : '&') + 'callback=' + callback;
    document.getElementsByTagName('head')[0].appendChild(script);
  });
})();

使用例:

const data = await load('http://api.github.com/orgs/kriasoft');

1
window[callback] = null関数のガベージコレクションを許可することを忘れないでください。
スキマスイッチ

3

これをできるだけ簡単に処理するためのライブラリを作成しました。外部にする必要はなく、1つの機能だけです。他の一部のオプションとは異なり、このスクリプトはその後にクリーンアップし、実行時にさらに要求を行うために一般化されています。

https://github.com/Fresheyeball/micro-jsonp

function jsonp(url, key, callback) {

    var appendParam = function(url, key, param){
            return url
                + (url.indexOf("?") > 0 ? "&" : "?")
                + key + "=" + param;
        },

        createScript = function(url, callback){
            var doc = document,
                head = doc.head,
                script = doc.createElement("script");

            script
            .setAttribute("src", url);

            head
            .appendChild(script);

            callback(function(){
                setTimeout(function(){
                    head
                    .removeChild(script);
                }, 0);
            });
        },

        q =
            "q" + Math.round(Math.random() * Date.now());

    createScript(
        appendParam(url, key, q), function(remove){
            window[q] =
                function(json){
                    window[q] = undefined;
                    remove();
                    callback(json);
                };
        });
}

2

JQueryを使用せずに呼び出すJavaScript例を以下に示しますJSONP

また、私のGitHubリポジトリを参照することもできます。

https://github.com/shedagemayur/JavaScriptCode/tree/master/jsonp

window.onload = function(){
    var callbackMethod = 'callback_' + new Date().getTime();

    var script = document.createElement('script');
    script.src = 'https://jsonplaceholder.typicode.com/users/1?callback='+callbackMethod;

    document.body.appendChild(script);

    window[callbackMethod] = function(data){
        delete window[callbackMethod];
        document.body.removeChild(script);
        console.log(data);
    }
}


0
/**
 * Get JSONP data for cross-domain AJAX requests
 * @private
 * @link http://cameronspear.com/blog/exactly-what-is-jsonp/
 * @param  {String} url      The URL of the JSON request
 * @param  {String} callback The name of the callback to run on load
 */
var loadJSONP = function ( url, callback ) {

    // Create script with url and callback (if specified)
    var ref = window.document.getElementsByTagName( 'script' )[ 0 ];
    var script = window.document.createElement( 'script' );
    script.src = url + (url.indexOf( '?' ) + 1 ? '&' : '?') + 'callback=' + callback;

    // Insert script tag into the DOM (append to <head>)
    ref.parentNode.insertBefore( script, ref );

    // After the script is loaded (and executed), remove it
    script.onload = function () {
        this.remove();
    };

};

/** 
 * Example
 */

// Function to run on success
var logAPI = function ( data ) {
    console.log( data );
}

// Run request
loadJSONP( 'http://api.petfinder.com/shelter.getPets?format=json&key=12345&shelter=AA11', 'logAPI' );

なぜwindow.document.getElementsByTagName('script')[0];ありませんかdocument.body.appendChild(…)
スキマスイッチ

ガベージコレクションを実行できるようlogAPInull、いつに設定するべきではありませんか?
スキマスイッチ

0

NPMでES6を使用している場合は、ノードモジュール「fetch-jsonp」を試すことができます。Fetch API通常のXHR呼び出しとしてJsonP呼び出しを行うためのサポートを提供します。

前提条件:isomorphic-fetchスタックでノードモジュールを使用する必要があります。


0

ES6バージョンのsobstelのいい答えを貼り付けるだけです。

send(someUrl + 'error?d=' + encodeURI(JSON.stringify(json)) + '&callback=c', 'c', 5)
    .then((json) => console.log(json))
    .catch((err) => console.log(err))

function send(url, callback, timeout) {
    return new Promise((resolve, reject) => {
        let script = document.createElement('script')
        let timeout_trigger = window.setTimeout(() => {
            window[callback] = () => {}
            script.parentNode.removeChild(script)
            reject('No response')
        }, timeout * 1000)

        window[callback] = (data) => {
            window.clearTimeout(timeout_trigger)
            script.parentNode.removeChild(script)
            resolve(data)
        }

        script.type = 'text/javascript'
        script.async = true
        script.src = url

        document.getElementsByTagName('head')[0].appendChild(script)
    })
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.