第23話:jQueryを利用した通信処理
目次
マンガ
マンガ台詞
説明
この章では、『jQueryを利用した通信処理』について学びます。
前章で紹介したように、『jQuery』には、Webページに様々なエフェクトを加えたり、要素を操作したりする仕組みが用意されています。それだけでなく、『jQuery』は、ページを移動することなく、バックグラウンドでサーバーのファイルを読んだり、サーバーにデータを送ったりする仕組みを持っています。このような、ページ遷移を伴わない通信処理と、その仕組みを利用したWebページのプログラミングのことを、『Ajax』と呼びます。
それでは以下、『jQueryを利用した通信処理』と『Ajax』について解説していきます。
『Ajax』とは?
新しいWebページをロードすることなく、バックグラウンドでサーバーと通信を行い、Webページを動的に書き換える処理を『Ajax』と呼びます(『Ajax』は、エイジャックスという読み方が一般的)。
『Ajax』は『Asynchronous JavaScript + XML』の略です。日本語に訳すならば『非同期にJavaScript とXMLファイルを使って通信を行う』といった意味になります。『XML』は、HTMLのような、テキストファイルの形式の1つです。
『Ajax』は、現在では『XML』に限らず、サーバーとテキスト形式のファイルのやり取りを行いながら、Webページの情報を更新していく方法全般を指します。
『jQuery』には、この『Ajax』を手軽に行うためのメソッドが用意されています。以下、そのメソッドを使った通信方法を紹介していきます。
『jQuery』の通信処理
通信を行う『ajax』メソッドは、オブジェクトを引数に取ります。この引数の、いくつかのオプションを紹介します。全てを設定する必要はありません。必要に応じて値を設定します。
$.ajax({ url: "https://www.google.com/search", // URL(最低限これは必要) data: "q=crocro&lang=ja", // 送信するデータ type: "GET", // GETかPOST(非設定時はGET) cache: true, // 通信結果をキャッシュするか(非設定時はtrue) timeout: 1000, // タイムアウトのミリ秒 username: "", // 認証が必要な場合のユーザー名 password: "" // 認証が必要な場合のパスワード }).done(function(data, textStatus, jqXHR) { // 成功時の処理 }).fail(function(jqXHR, textStatus, errorThrown) { // 失敗時の処理 }).always(function (data_or_jqXHR, textStatus, jqXHR_or_errorThrown) { // 成功、失敗に関わらず実行する処理 ); });
『jQuery』には、『ajax』メソッド以外にも通信用のメソッドが用意されています。詳しくは、『jQuery』の解説サイトや解説本を参考にしてください。
セキュリティの問題
この『ajax』メソッドですが、セキュリティの問題で、同じサーバー上にあるファイルしか基本的に取得できません。また、ブラウザによっては、ローカルで読み込めません。なので、機能を試す場合は、サーバー上にHTMLファイルと読み込むファイルをアップロードしてから実験を行なってください。
用意するデータの『文字コード』
さて、『Ajax』でのファイルの取得ですが、「日本語の入ったファイル」を取得する場合には注意が必要です。『Ajax』の通信処理は、ファイルの文字コードを『UTF-8』と想定して行われます。そのため、取得したファイルが『UTF-8』以外のファイルだった場合に、文字化けしたりします。
マンガ中のプログラムの解説
それでは、マンガ中に出てきたプログラムを元に解説を行っていきます。
【data1.csv】
遊,6,12,8 麗,98,89,92 守,73,82,74
【data2.csv】
安見 遊,女の子 高美舎 麗,女の子 内木 守,男の子
『data1.csv』『data2.csv』ともに、文字コードが『UTF-8』のテキストファイルです。
以下、プログラムです。全てのファイルを同じサーバー上にアップロードしてから実行してください。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script> // 引数『no』を取る関数(引数に応じて『data1.csv』『data2.csv』を取得) function hyouji(no) { // 『jQuery』の『ajax()』メソッド $.ajax({ url: "data" + no + ".csv" // ファイル名 }).done(function(result) { // 成功時の処理、引数『result』を取る無名関数 // 『result』には取得した文字列が格納されている $("#data").text(result); // id『data』の要素の文字列に設定 }); } </script> </head> <body> <input type="button" onClick="hyouji(1);" value="表の表示1"> <input type="button" onClick="hyouji(2);" value="表の表示2"> <pre id="data"></pre> </body> </html>
『jQuery』を利用した処理なので、まずは『<script>』タグの『src』属性を利用して『jQuery』を読み込んでいます。
ブラウザでHTMLファイルを読み込むと、画面には『表の表示1』『表の表示2』という2つのボタンが表示されます。
『表の表示1』ボタンをクリックすると、『hyou』関数を利用して『data1.csv』を読み込み、『<pre id="data"></pre>』のタグ内の文字列として表示します。『表の表示2』ボタンをクリックすると『data2.csv』を読み込み、同じ居場所に表示します。
『hyou』関数内では『$.ajax()』という、『jQuery』の『ajax』メソッドを利用しています。このメソッドは、オブジェクトで引数を取ります。通信処理のように、多くの設定が必要になるメソッドでは、引数にオブジェクトを取ることが多いです。
今回の処理では、『ajax』メソッドの引数には『url』を設定しています。
『url』には、ファイルのパスを記入します。この場合、Webページと同じドメイン上のファイルは指定できますが、別のドメインのファイルは指定できません。これはセキュリティ上の制約です。
『done』には、通信が成功した際の処理を関数で設定します。ここでは、『result』という引数を設定した無名関数を用意しています。引数『result』には、通信の結果取得したテキスト形式のデータが入ります。
このプログラムでは、『$("#data").text(result)』とすることで、id『data』の要素の文字列部分に、引数『result』の内容を挿入しています。
『非同期通信』
『ajax』の『success』に指定した関数は、ブラウザが通信を完了した後に実行されます。JavaScriptのプログラムは、この実行を待たずに、次の処理に進みます。
以下、実際に実行される順番を解説します。
// 領域1 $.ajax({ type: "GET", url: "data1.csv" }).done(function(result){ // 領域3 $("#data").text(result); }); // 領域2
【処理順番】
- 『領域1』が実行される。
- 『領域2』が実行される。
- 通信完了後に『領域3』が実行される。
このように、プログラムの処理とは独立して通信が行われることを『非同期通信』と呼びます。
こういった非同期な通信を行うことで、『通信が完了するまでブラウザが固まってしまう(操作不能になる)』ことを防いでいます。
セキュリティ
『Ajax』で通信を行う際は、セキュリティに気をつける必要があります。
サーバー上のCGIとやり取りする場合は、特に注意が必要です。セキュリティに関しては、今回の講座の本題から外れますので説明は割愛します。
基本的には、クライアント側とサーバー側の両方で、データを送る時、受け取る時に、問題になるデータがないか確認する必要があります。
どういったデータがセキュリティ的に問題があるのかは、使用しているクライアントソフトとプログラミング言語、またサーバー側のプログラミング言語と使用ソフトによって異なります。開発者は、これらのセキュリティ情報を、日々集め続ける必要があります。
ネットのITサイトやセキュリティサイトを当たり、必要に応じて知識を増やしていってください。
『クロスドメイン』
JavaScriptを使い、データをサーバーから取得する際には、セキュリティ上の制約があります。
JavaScriptでは、Webページが読み込まれた『ドメイン』としか通信ができません(『ドメイン』は、URLの『https://www.google.com/』の『www.google.com』の部分です)。
『Ajax』は、『XMLHttpRequest』というオブジェクトを利用して通信を行います。このオブジェクトは、Webページが読み込まれた『ドメイン』以外とは通信を行いません。そのため、それ以外の『ドメイン』にあるファイルには、アクセスできません。
Webページを読み込んだ以外の『ドメイン』と通信することは、『クロスドメイン』通信と呼ばれています。『クロスドメイン』通信は、JavaScriptでは基本的に行えませんので注意が必要です。
ローカルでの制約
ブラウザによっては、ローカルにHTMLファイルがある場合、ローカルにあるファイルを読み込むことができません。通信系のテストは、サーバー上で行なうのがよいです。
ローカルでサーバー環境を作る必要がある場合は、『nginx』や『XAMPP』などを導入するとよいです。JavaSriptの実行確認だけなら『nginx』が軽くてよいです。
『JSON』
WebページのJavaScriptでデータを取得する際には、『JSON』や『JSONP』と呼ばれるデータ形式がよく使われます。
かつては『XML』形式のデータが多かったのですが、『XML』は冗長でファイルサイズが大きいので、最近では『JSON』や『JSONP』を使うケースが増えています。WebAPIと呼ばれる、Web上に公開されている便利なツールの多くが、『JSON』や『JSONP』に対応しています。
『JSON』は、JavaScriptのオブジェクトのように書いたテキストデータです。
以下、サンプルとして『data.json』というファイルの内容を掲載します。
{"seito" : [ { "namae" : "Yasumi Yuu", "seibetu" : "Woman" }, { "namae" : "Takabisya Rei", "seibetu" : "Woman" }, { "namae" : "Utiki Mamoru", "seibetu" : "Man" } ]}
『Ajax』では、このファイルを読み込んだあと、JavaScriptのオブジェクトに変換して利用します。
『JSON』の実例
上記のファイルを読み込んで、表示するプログラムを以下に示します。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script> function hyouji() { $.getJSON("data.json", function(json){ for (var i = 0; i < json.seito.length; i ++) { var seito = json.seito[i]; $("#data") .append(seito.namae + " : " + seito.seibetu) .append("<br>"); } }); } </script> </head> <body> <input type="button" onClick="hyouji();" value="表の表示"> <div id="data"></div> </body> </html>
『jQuery』の『getJSON』というメソッドを利用しています。第1引数にはファイルのパスを、第2引数には、データ取得後の処理を、無名関数で記述しています。
データ取得後の処理を行う無名関数は、『json』という引数を取っています。この『json』には、取得した『data.json』を、JavaScriptのオブジェクトとして解釈したデータが入っています。
この『json』の内容は、以下の値と同じです。
var json = {"seito" : [ { "namae" : "Yasumi Yuu", "seibetu" : "Woman" }, { "namae" : "Takabisya Rei", "seibetu" : "Woman" }, { "namae" : "Utiki Mamoru", "seibetu" : "Man" } ]};
このデータの内容をツリー状に表記すると、以下のようになります。
- seito
- seito[0]
- seito[0]["namae"] = "Yasumi Yuu"
- seito[0]["seibetu"] = "Woman"
- seito[1]
- seito[1]["namae"] = "Takabisya Rei"
- seito[1]["seibetu"] = "Woman"
- seito[2]
- seito[2]["namae"] = "Utiki Mamoru"
- seito[2]["seibetu"] = "Man"
- seito[0]
取得したデータは、上記のような構造になっています。そのため、『for』文の中で、『json.seito』を配列として扱っています。
『json.seito.length』は、配列の要素数です。『var seito = json.seito[i];』の『var seito』は、『namae』と『seibetu』という2つのキーを持つオブジェクトです。そのため、以下は同じ内容になります。
var seito = json.seito[0];
var seito = { "namae" : "Yasumi Yuu", "seibetu" : "Woman" };
このようにして取得した、『json』の各データを、id『data』の要素に追加しています。
$("#data") .append(seito.namae + " : " + seito.seibetu) .append("<br>");
『append』メソッドは、セレクタで選択した要素の配下に、指定のHTMLを追加する命令です。ここでは、『seito.namae + " : " + seito.seibetu』として、名前と性別を追加しています。また、『<br>』を加えることで、改行も追加しています。
この『JSON』の取得は、『XMLHttpRequest』というオブジェクトが利用されています。そのため、同じ『ドメイン』のファイルしか取得できません。また、Webブラウザによっては、ローカルでは動作しません。
『JSONP』
『JSON』は便利ですが、『クロスドメイン』の制約があります。しかしプログラムによっては、他のドメインのサーバーからデータを読み込んで利用したい場合もあります。
そういった場合によく使われるのが、『JSONP』と呼ばれるデータ形式です。
『JSONP』は、『JSON』のデータを少しだけ変更したテキストデータです。
jsonCallback( {"seito" : [ { "namae" : "Yasumi Yuu", "seibetu" : "Woman" }, { "namae" : "Takabisya Rei", "seibetu" : "Woman" }, { "namae" : "Utiki Mamoru", "seibetu" : "Man" } ]} )
『JSON』との違いは、『jsonCallback』のように関数を記述して、その引数としてデータが書かれている点です。
この『JSONP』のデータは、完全なJavaScriptのプログラムです。そのため、『<script>』タグをプログラムから追加することで、外部JavaScriptファイルとして読み込めます。
外部JavaScriptファイルを読み込む際は、『ドメイン』が同じである必要はありません。そのため、『クロスドメイン』の制約に引っ掛からずに、データを読み込めます。
『JSONP』の内部処理の解説
さて、『JSONP』では、データ全体を関数の呼び出し形式でくくりました。このデータが読み込まれた際に、何が起こるのでしょうか?
データの読み込みが完了して、『<script>』タグがWebページに追加されると、『jsonCallback』関数が呼び出されます(この関数の名前は任意に決めて構いません)。
元々のプログラム中に『function jsonCallback(data) {}』という関数があれば、取得したデータを引数としてその関数を実行します。
その結果、『function jsonCallback(data) {}』関数の引数『data』は、受け取ったデータそのものになります。『jsonCallback』内では、この受け取ったデータを元に、様々な処理を行います。
『Flickr』のWebAPIを使った『JSONP』の実例
以下、『Flickr』のWebAPIを使って猫の画像を表示するプログラムを示します。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script> function hyouji() { $.getJSON( "https://api.flickr.com/services/feeds/photos_public.gne?tags=cat&format=json&jsoncallback=?", function(json){ for (var i = 0; i < json.items.length; i ++) { var item = json.items[i]; $("<img/>") .attr("src", item.media.m) .appendTo("#data"); } } ); } </script> </head> <body> <input type="button" onClick="hyouji();" value="画像の表示"> <div id="data"></div> </body> </html>
(『Flickr』の戻り値によっては、Internet Explorerでエラーが起こるケースもあります。その際は、『tags=cat』の『cat』を、他の単語に変えるか、Google ChromeやMozilla Firefoxを使ってみてください)
上記のプログラムのポイントは2つです。
1つめは、指定しているURLのクエリーの一部が『jsoncallback=?』となっているところです。
WebAPIでは、コールバック用のメソッド名をCGIの引数として指定するようになっています。しかし、メソッド名を指定するパラメータが何なのかは、WebAPIによって異なります。
『Flickr』の場合、コールバック用のメソッド名を指定する場所は『jsoncallback=~』となります。この場所に『jsoncallback=?』と書いておけば、『jQuery』は『?』の位置にメソッド名を書き込み、URLを完成させてから、ファイルを読み込みます。
この『?』の位置には、『jsonp1271964453817』のようなメソッド名が、自動で作成されて代入されます。
【コールバック関数の設定前のURL】
https://api.flickr.com/services/feeds/photos_public.gne?tags=cat&format=json&jsoncallback=?
【コールバック関数の設定後のURL】
https://api.flickr.com/services/feeds/photos_public.gne?tags=cat&format=json&jsoncallback=jsonp1271964453817
2つめは、『function(json)』の部分です。成功時に呼び出される関数の第1引数に、『JSONP』を解析したオブジェクトが入ってます。このオブジェクトを利用して、データを読むことができます。
サンプルの入手
以下は、今回出てきたサンプルです。
注意事項
- 通信関係のプログラムは、ブラウザのセキュリティの関係で、ローカル上では動作せず、サーバー上でしか動作しません。
- そのため、実行する際は、適当なサーバー(レンタルサーバーなど)にアップロードするか、PCにサーバーソフトを導入して、実行することになります。
- ローカルにサーバーを立てるには「XAMPP」などを使うとよいでしょう。
ZIPでまとめてダウンロード (右クリックから保存してください)
『sample1.html』(『Ajax』によるデータの取得)を表示
『data1.csv』(データ1)(右クリックから保存してください)
『data2.csv』(データ2)(右クリックから保存してください)
『sample2.html』(『JSON』によるデータの取得)を表示
『data.json』(『JSON』データ)(右クリックから保存してください)
『sample3.html』(『JSONP』によるデータの取得)を表示
プログラムの中身を見たい場合は、それぞれのHTMLファイルをブラウザで開いたあと、右クリックをして『ソースの表示』を選択してください。
メモ帳で、ファイルの中身を見ることができます。