こんにちは、
JSONとは
JSONについては第9回でも少し触れていますが、
JSON
JSONはそのシンプルさから多くの言語でネイティブにサポートされており、
["aaa", "bbb", "ccc"]
{"aaa":1, "bbb": 2, "ccc": 3}
{"num": [1, 2, 3], "abc":["a", "b", "c"]}
JavaScriptとJSONの書式はよく似ていますが、
JSONはそういった曖昧さを排除してデータ記述言語としての精度と、
また、
JSONPとは
JSONPはJSON with Paddingの略称です。Paddingは
先ほどのJSONをJSONPらしくしてみると下記のようになります。
callback( {"num":[1,2,3], "abc":["a","b","c"]} );
{}で囲まれた部分がJSON形式になっており、
JSONPの理解
JSONPがなぜドメインを超えてデータをやり取りすることができるのか、
まず、
// 宣言なしで変数に代入すると常にグローバル変数に
global1 = 1;
// 関数の外では宣言をしてもグローバル変数に
var global2 = 2;
// グローバルオブジェクトのプロパティもグルーバル変数
window.global3 = 3;
// 関数の外では関数宣言もグローバル関数に
function global4(local1){ // 当然、引数はローカル変数
// 関数の中の宣言付き変数はローカル変数に
var local2 = 2;
var local3 = function(){
var local4 = 4;
// varをつけ忘れると常にグローバルに
global5 = 5;
};
var local5 = function(){
// 当然、local4は参照できない
alert(typeof local4); // undefined
alert(global5); // 5
}
local3();
global6();
}
global4(1);
さらに、
<script>
global1 = 1;
</script>
<script>
alert(global1); // 1
</script>
上記はscript要素に直書きしていますが、
<script src="global1.js">
<!--中身は global1 = 1; とだけ書かれたJSファイル-->
</script>
<script>
alert(global1); // 1
</script>
さらに、
<script src="http://example.com/global1.js">
<!-- global1 = 1; とだけ書かれたJSファイルがあると仮定する -->
</script>
<script>
alert(global1); // 1
</script>
見事、
しかし、
さて、
function loadJS(src){
var script = document.createElement('script');
script.src = src;
document.body.appendChild(script);
}
loadJS('global1.js');
alert(typeof global1); // undefined
jsファイルは読み込みましたが、
- loadJS('global1.
js'); - var script = document.
createElement('script'); - script.
src = src; - document.
body. appendChild(script); (global1. jsの読み込み開始)
- var script = document.
- alert(typeof global1); // undefined
(global1. jsを読み込み中)
(global1. jsの読み込み完了) - global1 = 1;
global1に1が代入されるのはglobal1.
JavaScriptはシングルスレッドなので、
読み込みを待つ方法としてはscript要素のonloadイベントを使う方法もありますが、
コールバックの仕組みも単純です。まず、
global2(2);
このglobal2.
function loadJS(src){
var script = document.createElement('script');
script.src = src;
document.body.appendChild(script);
}
var global2 = function(data){
alert(data); // 2
};
loadJS('global2.js');
こうすることで、
- var global2 = function(data) …
- loadJS('global2.
js'); - var script = document.
createElement('script'); - script.
src = src; - document.
body. appendChild(script); (global2. jsの読み込み開始)
- var script = document.
(global2. jsの読み込み完了) - global2(2);
- alert(data); // 2
さて、
function loadJS(src){
var script = document.createElement('script');
script.src = src;
document.body.appendChild(script);
}
var jsonp_callback = function(data){
//
};
loadJS('jsonp.api?callback=jsonp_callback');
var jsonp_callback2 = function(data){
//
};
loadJS('jsonp.api?callback=jsonp_callback2');
JSONPの活用例
では、
<ul id="tinyurls">
<li><a href="http://tinyurl.com/2b9hf8c">http://tinyurl.com/2b9hf8c</a></li>
<li><a href="http://tinyurl.com/242xed7">http://tinyurl.com/242xed7</a></li>
<li><a href="http://tinyurl.com/yas6fwn">http://tinyurl.com/yas6fwn</a></li>
</ul>
このリンクを展開してみましょう。
(function(){
var REURL_API = 'http://ss-o.net/api/reurl.json';
var tinyurls = document.getElementById('tinyurls');
var links = tinyurls.getElementsByTagName('a');
var TEXT = ('textContent' in document.body) ?
'textContent' : 'innerText';
for (var i = 0, len = links.length;i < len; i++) {
(function(i){
var a = links[i];
var url = encodeURIComponent(a.href);
var script = document.createElement('script');
// callbackの名前をユニークに
var callbackName = 'callback' + i;
script.src = REURL_API + '?url=' + url +
'&callback=' + callbackName;
// callbackの名前でグローバル関数を定義
window[callbackName] = function(data){
a.title = data.url;
a[TEXT] = data.url;
};
document.body.appendChild(script);
})(i);
}
})();
ここで、
さて、グローバルオブジェクト.コールバック関数名
のようにして呼び出す方法がお薦めです。
(function(){
window.ReurlAPI = {}; // グローバルオブジェクトを用意
var REURL_API = 'http://ss-o.net/api/reurl.json';
var tinyurls = document.getElementById('tinyurls');
var links = tinyurls.getElementsByTagName('a');
var TEXT = ('textContent' in document.body) ?
'textContent' : 'innerText';
for (var i = 0, len = links.length;i < len; i++) {
(function(i){
var a = links[i];
var url = encodeURIComponent(a.href);
var script = document.createElement('script');
// callbackの名前をユニークに
var callbackName = 'callback' + i;
script.src = REURL_API + '?url=' + url +
'&callback=ReurlAPI.' + callbackName;
// callbackの名前でグローバル関数を定義
ReurlAPI[callbackName] = function(data){
a.title = data.url;
a[TEXT] = data.url;
};
document.body.appendChild(script);
})(i);
}
})();
JSONPのセキュリティ
JSONPはJavaScriptの仕様の穴を突いているといっても過言ではないような技術です。そのため、
なお、
また、
JSONPを利用する場合
前述の通り、
また、
加えて、
JSONPを提供する場合
JSONPには特定のサイトからのリクエストに対してのみデータを返すように制御する仕組みなどはありません。JSONPで提供するデータはあらゆるドメインから利用可能になります。当然のことですが機密情報をJSONPのデータに含めてはいけません。
また、
さらに、[a-zA-Z0-9_.\[\]]
など)。
ちなみにJSONPを提供する場合、text/
で返すのが良いでしょう。JSONのContent-Typeはapplication/
ですが、
まとめ
今回はJSONPの基礎を詳しく解説してみました。JSONPが実は単なるJavaScriptファイルの読み込みに過ぎない実に簡単な仕組みであることは理解頂けたのではないかと思います。
次回はXMLHttpRequestを中心に非同期処理を掘り下げていく予定です。