Ajax通信(その1)
とうとう出てきたよ、Ajaxの「肝」である通信部分!
今回のこの通信部分のセクションについては、load、html、ajaxというメソッドが登場するが、最も細かい操作が可能なタイプはajaxメソッドだけっぽい?
正直ajaxメソッド以外は知ってても知らなくてもよさげな感じなので、loadとhtmlは割愛しちゃう。
さて、例のサイトのajaxメソッドをちょこっと試してみたらここに記述されている内容だけでは実現したい処理ができず、またそこから先の「こーやればできるんじゃね?」的な推測もできなかった。
結局、調べなきゃならんかったので、その過程で推測できたことに関しても記述していく。(本当はjQueryのソースコード読むべきだけど。)
Ajaxとは
この通信部分については、4、5年前に少しだけ書籍で読んだことはあったんだけど、当時の印象は「ややこしすぎる」の一言に尽きた。いずれ主流になる技術の根幹部分だという認識はあったけど、絶対もっと使いやすいライブラリが出てくるとも思ってたのでそのときはスルー。
ではAjaxについて自分が持っている認識を。
1はまぁいいわな。
1.非同期通信であり、通常の POST や GET と違い、ページの再描画が発生しない。
2.セキュリティ上、同一ドメインへのリクエストしかできない。(クロスドメインの問題)
3.でも2を回避する方法もある。(キーワード:「JSONP」)
4.でも、結局クロスドメインなのでJSONPを使う時は気をつけてね。
問題は2だ。
ここで例のサイトのサンプルだとうまくいかなかった過程を書いておこう。
少し前に郵便番号取得のサンプルを作ったので、最初はこれをベースに通信をAjax化させてみようとしてみたら、うまくいかない。。
通信自体は成功している?ように見えるんだが、肝心要のデータが取得できない。
そこでいろいろ調べてみたところ、同一ドメインでないとうまく動かないとのこと。。
サンプルのHTMLファイルはいつもローカルファイルとして作成して、それをブラウザで表示しているので正常に動くわけがなかったというオチ。
同一ドメインでないと通信できないんじゃ、俺がJavascriptを本格的に勉強しようと思った動機(GUIアプリのプロトタイプをローカルでサクっと作って、最後にWebサービスとして通信処理をAjaxで実装すればWebアプリのできあがり!)が実現できない。
なんか抜け道があるだろうと思って調べたら、案の定あったという流れ。
それが3のキーワードである「JSONP」。難しいけど一応簡単にまとめておいてみよう。
scriptタグにはsrc属性というものがある。
このsrcには、読み込み対象になるJavascriptファイルを指定するわけだが、
別のドメインのJavascriptファイルを読み込ませることができる。
(今まで自分が作ってきたサンプルにもgoogleのjavascriptファイルを読み込ませているし。)
土台となる考え方
scriptタグにはsrc属性というものがある。
このsrcには、読み込み対象になるJavascriptファイルを指定するわけだが、
別のドメインのJavascriptファイルを読み込ませることができる。
こんな感じに。
<script type="(略)" src="http://www.hoge.com/fuga.js"></script>
この性質(正直「穴」といってもいいんじゃなかろうか?良く知らんけど…)を利用すると、仮に「http://www.hoge.com/fuga.js」のJavascriptファイル内に記述されているデータについては、クロスドメインでもアクセスが可能になる。
仮に上記のfuga.jsがこんなファイル内容で記述されていたとする。
var primeMinister = "伊藤博文";
更にだ。上述のファイルは必ずしも「スクリプトファイル」である必要はない。
結果的に、「javascriptとして解釈可能な文字列を返すURL」であれば、それがファイルだろうがサービスだろうが問題ない。
つまり、「*.txt」でもいいし、「*.cgi?nth=1」なんかでもわけだ。こんな風に。
<!-- ①静的なテキストファイルをスクリプトとして読み込む --> <script type="(略)" src="http://www.hoge.com/fuga.txt"></script> <!-- ②Webサービスに、「nth=1」というパラメータを渡し、返される結果文字列をスクリプトとして読み込む --> <script type="(略)" src="http://www.hoge.com/fuga.cgi?nth=1"></script>
特に、②のscriptタグの記述の結果、何が起きるかについて具体的に説明する。
これは、"nth"という名前のリクエストパラメータをGETで受け取る仮想的なWebサービスで、そのWebサービスが返却する文字列はパラメータによって、
//nth=1の時 var primeMinister = "伊藤博文";
であったり、
//nth=93の時 var primeMinister = "愚かな総理";
であったりと、動的に変化する結果をブラウザに処理させることになる。
これでクロスドメインのWebサービスとのデータのやり取りがなんとか可能になる。
ちなみにこのWebサービスはGETでパラメータを渡しているけども、どうやらPOSTでの送信も可能らしい。詳細はわからんけど。
「土台」だけだと困る
但し、Ajaxは非同期通信であるので、読み込んだスクリプトは実行されるとすぐに無効な状態になってしまう。
だから取得データをあとでゆっくり処理する、なんてことができない。
この問題を解決するための仕組みとして、あらかじめコールバック関数を定義しておき、サーバ側は「クライアントに渡したいデータを第一引数にしたコールバック関数」を実行するスクリプトを返す。
1.通信が成功した時に実行するコールバック関数をあらかじめ定義しておく。
2.クロスドメインのURLをsrc属性に指定したscriptタグを読み込ませる。
(Webサービス側は、1で定義したコールバック関数の第1引数に返却データを渡した文字列を返す。)
3.2で読み込んだスクリプト(コールバック関数)が返却したいデータとともに実行され、必要な処理が実行される。
4.3までの処理が完了したら1のコールバック関数の定義と、2のscriptタグを動的に削除する。
(ブラウザのメモリ上に残さない。)