第23話:jQueryを利用した通信処理

第4部 ライブラリ

目次

マンガ

マンガ

マンガ

マンガ

マンガ台詞

【1Page】
アイコン先生:Webページの操作を 劇的に簡単にする『jQuery』だが
    実はもう1つ 便利な機能がある
    それは通信機能だ
アイコン遊:通信機能?
アイコン先生:パソコンやサーバーから ファイルを読み込む機能だ
アイコン遊:どう便利なの?
アイコン先生:たとえば CSVのデータを 置いておく
    そのファイルを 必要に応じて 読み込めれば便利だ
        【data1.csv】
        遊,6,12,8
        麗,98,89,92
        守,73,82,74

        【data2.csv】
        安見 遊,女の子
        高美舎 麗,女の子
        内木 守,男の子
            上記CSVファイルは
            『UTF-8』で書く
【2Page】
        <!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);
                    });
                }
                </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>
        『data1.csv』を取得して id『data』内に挿入
        『data2.csv』を取得して id『data』内に挿入
アイコン遊:なるほど
    必要に応じて カンニングする ようなものね
アイコン先生:たとえが 悪いなあ
【3Page】
アイコン先生:それじゃあ少し 説明するぞ
    複雑に見えるけど やっていることは単純だ
        $.ajax({
            url: "data" + no + ".csv"
        }).done(function(result) {
            $("#data").text(result);
        });
    『ajax』メソッドの引数は 『{url:値}』という
    オブジェクトになっている
    ここには各種の設定を書く
    結果の受け取りは『done』の 引数にした関数で行なう
    これは通信成功時の処理だ
    取得した文字列『result』は 『jQuery』の『text』メソッドで
    id『data』の文字列にしている
アイコン先生:というわけで 動的にデータを読んだり 送ったりすることも
    『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. 『領域1』が実行される。
  2. 『領域2』が実行される。
  3. 通信完了後に『領域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"

取得したデータは、上記のような構造になっています。そのため、『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ファイルをブラウザで開いたあと、右クリックをして『ソースの表示』を選択してください。

メモ帳で、ファイルの中身を見ることができます。