JSONPって何?(jQueryで簡単にJSONP)
結論から言うと、jQueryを使えばJSONPを扱うのは簡単でです
var uri = "http://[APIのURI]?[callback指定パラメータ名]=?" $.getJSON(uri, params, function(data){ // data処理 })
しかし、このメソッドが何を簡略化しているのか知らなければ、
jQueryが使えない場合に応用できません
そこで今回は、自分がJSONPの必要性に気付いたところから、
その仕組みを理解していった経過を、メモに残しておきます...φ(・ω・`)
関連:群馬Web勉強会(on 2010/08/21)まとめ - どっかのBlogの前置きのような
Lv0:発端
TokyoCabinetにデータを格納した検索コアAPIと、
Railsのフロントを連動させて、データ検索システムを作る、
というのが今の私の仕事です
Browser -> Rails -> APIProxy(HTTPRequest) -> API(JSON)
なので、勉強会ではその延長で、RDGC+API+jQueryの話をしようと、
(iOSアプリがよくやるような)ローカルHTMLからサーバAPIを叩くデモを作ったのですが、
当然のように全く動きませんΣ(・ω・ノ)ノ
というのも、Ajaxで使われるXMLHttpRequestは、
セキュリティポリシーにより、別ドメインへのリクエストが送信できないのです
仕事のシステムでは送信先がRails=同じサーバで、
内部的にリクエストを処理しているからOKなのですが、
デモはHTMLから直にサーバAPIを叩こうとするのでNGなわけです
これをうまく処理してくれるのが「JSONP」という仕組み、
ということになります
Lv1:静的に対処する
先ほどの問題はあくまでXMLHttpRequestの仕様であって、
Javascript自体は別ドメインにあっても構いません
実際、MSやGoogleが提供するjQueryライブラリを、
ローカルHTMLのscriptタグに書いても動作します
そこで、サーバAPIが返すものを「JSON」から「JavaSscriptの断片」に変更します
// 修正前 {name: parrot, lv: 10} // 修正後 hoge({name: parrot, lv: 10})
後者はfunctionをJSONで呼び出しているコードです
ということは、あらかじめそのfunctionを静的に書いておけば、
渡されたデータを受け取って処理できます
<script type="text/javascript"> function hoge(data){ // dataの処理 } </script> <script type="text/javascript" src="http://someserver/api?name=parrot" />
ただし、これだとfunctionの名称が固定になってしまい、
すでにあるfunction名と被る危険性があるので、
API側でfunction名を指定できるのが一般的なようです
<script type="text/javascript" src="http://someserver/api?callback=hoge&name=parrot" />
Lv2:動的に対処する
Lv1のやり方だと、あらかじめ決まったAPIパラメータしか渡せません
つまり、buttonをトリガーにして、その時の入力パラメータを元に、
動的にAPIを叩く、ということができないのです
Blogパーツ等で、最近のデータ5件を取ってくる、
なんてケースにはLv1の方法で十分なのですが、
通常は何らかの動的処理が入るでしょう
そこで・・・
scriptタグでしか外部APIが呼べないなら、 scriptタグそのものを動的生成すればいいじゃなーい(`・ω・´)
・・・と考えた人がいたわけです
つまり、button等をトリガーにして、
動的にscriptタグを生成し、HTMLのDOMにくっつけることで、
半ば無理矢理ながら動的に処理しよう・・・と
しかし、これだけだと例えばbuttonが押されるたびにscriptタグが増えてしまうので、
実際は不要になったところで、タグをDOMから削除する処理も必要になります
Lv3:とりあえずまとめてみる
- APIのJSONを処理したいfunctionを先に用意
- APIのURIにfunction名パラメータを含める
- トリガーによって動的に前項をsrcに指定したscriptタグを生成
- scriptタグをHTMLのDOMにappend
- 戻ってきたデータを処理
- scriptタグを削除
文章で書くとこれだけですが、
実際に実装するとなるとかなり面倒ですよね・・・(´・ω・`)
Lv4:jQueryを使う
こういった「面倒な処理」を全部面倒見てくれるのが、
冒頭のgetJSONメソッド、ということになります
原理的にはここまで書いてきた物そのものです
var uri = "http://[APIのURI]?[callback指定パラメータ名]=?" $.getJSON(uri, params, function(data){ // data処理 })
URIのcallback指定パラメータ名に「?」を指定することで、
jQueryが動的にfunction名を生成し、一連の処理をした後、
scriptタグの削除までやってくれます
また、呼び出し先が同じドメインであった場合は、
自動で通常の呼び出しに置き換えて処理してくれるようで、
非常に助かります(`・ω・´) b
Lv5:セキュリティ的な問題
APIを実装する側は、引数をきっちり検証しないと、
いろいろな脆弱性を生む可能性があります
- サーバにダメージを与えるような引数を与える
- 戻り値のコードがブラウザで実行された時に何かが起こる
発表会で使ったAPIはこれらの検証を行ってないため、
主に後者の問題が発生するはずです
(不正スクリプトを実行する文字列をcallbackに与えると・・・)
これを防ぐため、function名で使える文字列や長さを制限し、
サーバ側できっちり検証することが重要です*1
一方、JSONPを利用する側としては、
サーバが「想定した通りの戻り値」を返すうちはいいですが、
ある日突然、何らかの不正なコードが返される可能性もあります
そもそもJSONPはある種のセキュリティを回避する手法なのですから、
これらのリスクを認識したうえで、必要な対策を講じておくことが必要でしょうね