JSONPのサポート
/* uupaa.js (C) uupaa */ var uud = document, uuw = window, uu; uud.head = uud.documentElement.firstChild; // document.head new function() { uuw.uu = { work: { id: { jsonp: 0 } // unique id }, jsonp: {}, // JSONP callback function holder uniqueID: function(key /* = "jsonp" */) { var id = this.work.id, k = key || "jsonp"; return (k in id) ? ++id[k] : (id[k] = 1); }, mix: function(base, flavor) { for (var p in flavor) { base[p] = flavor[p]; } return base; }, id: function(id) { return uu.idCache[id] || (uu.idCache[id] = uud.getElementById(id)); }, idCache: {}, /** JSONP request * * @param string url request url fragment. "http://example.com/cgi?key=value" * @param function fn callback function * @param object bindThis バインドするthisを指定します。 * @param string callbackKeyword コールバック関数名を変更する場合に指定します。デフォルトは"callback"です。 */ loadJSONP: function(url, fn, bindThis /* = undefined */, callbackKeyword /* = "callback" */) { var uid = uu.uniqueID("jsonp"), cbkey = callbackKeyword || "callback"; // add callback holder function uu.jsonp["_" + uid] = function(json) { fn.call(bindThis, json); uuw.setTimeout(function() { uud.head.removeChild(uu.id("uu_jsonp_" + uid)); // remove <script id="uu_jsonp_{uid} ...> delete uu.jsonp["_" + uid]; // suicide }, 10); }; // add <script id="uu_jsonp_{uid}" src="{url}&callback=uu.jsonp._{uid}"></script> uud.head.appendChild(uu.mix(uud.createElement("script"), { id: "uu_jsonp_" + uid, type: "text/javascript", charset: "utf-8" })).src = url + (url.lastIndexOf("?") === -1 ? "?" : "&") + cbkey + "=uu.jsonp._" + uid; } }; };
はてなブックマークをJSONPで取得するには、はてなブックマークエントリー情報取得API を参考に、こんな感じにします。
function hatebu(mix) { alert(mix.title); // タイトル alert(mix.count); // ブックマークしている合計ユーザ数 } var url = "http://d.hatena.ne.jp/uupaa/20080420/1208636929"; var jsonpURL = "http://b.hatena.ne.jp/entry/json/?url=" + encodeURIComponent(url); uu.loadJSONP(jsonpURL, hatebu);
しくみ
- head要素にscriptタグを追加し、srcにリクエストを記述します。(src="http://example.com/cgi?key=value&callback=uu.jsonp._連番)
uu.jsonp._連番() { JSONな文字列; };
- といったレスポンスが返ってきます。
- レスポンスの内容がJavaScriptコードとして解釈され、callback=で指定したコールバック関数(uu.jsonp._連番)が呼ばれます。
- uu.loadJSONP()の引数fnに指定した関数(hatebu)は、uu.jsonp._連番 関数内から間接的にコールされます。
- uu.jsonp._連番 関数は、head内に追加したscriptタグの削除や、uu.jsonp._連番 関数の後処理を行います。
反省会
- XMLHttpRequest との住み分けがいまいち
- ドメインまたぐかどうかだけが違い?
- scriptタグを使うJSONPはGETリクエストだけしか使えないが、XMLHttpRequestだとPOSTができる。XMLHttpRequestはよりREST向き。
- IEは、GETリクエストの最大長が2086byte(だっけ?)まで。2000byte以上ならXMLHttpRequestしかない。
- ドメインまたぐかどうかだけが違い?
- 良いところ
- その他
- document.head がどうしてもほしいので勝手に追加。地味に便利。