JQueryや他の外部ライブラリを使用せずにJavaScriptでクロスドメインJSONPリクエストを作成できますか? JavaScript自体を使用してから、データを解析し、使用できるようにオブジェクトにしたいと思います。外部ライブラリを使用する必要がありますか?そうでない場合、どうすればいいですか?
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
軽量の例(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
JSONPとは?
Jsonpで覚えておくべき重要なことは、実際にはプロトコルまたはデータ型ではないということです。そのただの方法スクリプトをオンザフライでロードし、ページに導入されたスクリプトを処理します。 JSONPの精神では、これはサーバーからクライアントアプリケーション/スクリプトに新しいjavascriptオブジェクトを導入することを意味します。
JSONPはいつ必要ですか?
これは、1つのドメインが同じページ内の別のドメインのデータに非同期でアクセス/処理できるようにする1つの方法です。主に、XHR(ajax)要求で発生するCORS(Cross Origin Resource Sharing)制限をオーバーライドするために使用されます。スクリプトのロードはCORSの制限を受けません。
方法
サーバーからの新しいjavascriptオブジェクトの導入はさまざまな方法で実装できますが、最も一般的な方法は、必要なオブジェクトが渡された「コールバック」関数の実行をサーバーに実装することです。コールバック関数は、クライアントで既に設定済みの関数であり、スクリプトでコールをロードしますscriptがロードされ、渡されたデータを処理します。
例:
誰かの家にあるすべてのアイテムを記録するアプリケーションがあります。アプリケーションがセットアップされ、メインベッドルームのすべてのアイテムを取得したい。
私のアプリケーションは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を設定するよりもはるかに安全です。これは、app.home.com
がapi.home.com
から必要なものをすべて取得できるため、api.home.com
がなくても、CORSがインターネット全体にアクセスできるからです。
上記の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に追加された直後に、スクリプト要素をDOMから削除できます。
script.parentNode.removeChild(script);
私の理解では、実際に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をロードして実行します。
以下のような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の使用方法について話す)
私はそれを行うための純粋なJavaScriptライブラリを持っています https://github.com/robertodecurnex/J50Npi/blob/master/J50Npi.js
それを見て、コードの使用または理解に支援が必要な場合はお知らせください。
ところで、ここに簡単な使用例があります: http://robertodecurnex.github.com/J50Npi/
/**
* 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つだけです。他のいくつかのオプションとは異なり、このスクリプトは自動的にクリーンアップされ、実行時にさらにリクエストを行うために一般化されます。
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);
};
});
}
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);
}
}
/**
* 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' );
NPMでES6を使用している場合、ノードモジュール「fetch-jsonp」を試すことができます。 Fetch API JsonP呼び出しを通常のXHR呼び出しとしてサポートします。
前提条件:スタックでisomorphic-fetch
ノードモジュールを使用する必要があります。
Sobstelの素敵な答えのES6バージョンを貼り付けるだけです。
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)
})
}