こわくないAjax 第1回 HTTPの仕組み
Ajaxの仕組みを理解するためには、HTTPの理解が必要になります。ブラウザとサーバーとの間でどのような通信が行われているかをイメージできるように、今回はまずHTTPの仕組みを解説していきます。
- カテゴリー
- JavaScript >
- 非同期通信
発行
はじめに
Ajaxとは、Asynchronous JavaScript + XMLの略称で、JavaScriptを使って非同期*でサーバーとやり取りをする通信のことです。
*補足:非同期とは
のちほど『同期と非同期』の項にて解説しますので、いまはわからなくても大丈夫です。まずは順を追って読み進めてください。
これまでHTMLとCSSだけを扱ってきたデザイナーやマークアップ・エンジニアが、jQueryを使った動きのあるUIを実装できるようになってきたころ、次のレベルに進む前に立ちはだかってくるのが『Ajaxの壁』ではないでしょうか。
このような人がAjaxを難しく感じてしまうのは、ブラウザとサーバーとの間でどのような通信が行われているかを、具体的にイメージできないことが原因のひとつではないかと考えます。なぜなら、筆者がそうだったからです。
jQueryを使えば、Ajaxを使った非同期通信の実装が簡単にできます。そのため、$.ajax()
に関するいくつかのオプションを指定するだけで、Ajaxのことがよくわかっていなくても、なんとなく実装できてしまうかもしれません。
例えば、example.php
から取得したHTMLを、idがresult
の要素内に表示する場合、jQueryならこんなに簡単に実装できます。
$.ajax({
url: 'example.php'
})
.done(function (data) {
$('#result').html(data);
});
しかし、あいまいな理解のままでは、少しでも処理が複雑になった途端にお手上げ状態になってしまいます。また、サーバーとの通信に関する知識がなければ、APIの仕様を自分で決めることもできませんし、既存のAPIのドキュメントの意味が理解できなかったり、サーバーサイド・エンジニアとの間で、うまく話を進められなかったりするかもしれません。
このシリーズでは、まずはAjaxの通信の仕組みそのものを詳しく解説したのち、jQueryの$.ajax()
の使い方を解説していきます。ブラウザとサーバーとの間でどんなやり取りが行われているのか、また、$.ajax()
が裏で何をしているのかを具体的にイメージしながら実装できるようになれば、シングルページアプリケーションのような、複雑なAjaxが必要になる場面でも、安心して実装できるようになるでしょう。
HTTPとは
Ajaxの理解のためには、インターネットそのものの仕組みを理解しておく必要があるため、ここでは最低限必要な知識について触れておきます。
World Wide Web(ウェブ)は、クライアントとサーバーが、HTTP(Hypertext Transfer Protocol)という通信方法の約束事(プロトコル)にしたがって、HTMLや画像などのデータを送受信することで成り立っています。
クライアントは、サーバーに要求を送り、結果を受け取って処理を行います*。
*注:クライアント
Webサイトの制作におけるクライアントとは、ブラウザのことですが、サーバーに要求を送り、結果を受け取って処理を行う機能を持つものは、ブラウザ以外にも存在するため、HTTPの解説では、それらを総称してクライアントと呼びます。
サーバーには、HTML、CSS、JavaScript、画像などの静的ファイルや、アプリケーションプログラム、データベースなどが保管されており、クライアントからの要求に応じて、必要なものを返します。
クライアントとサーバー間のやり取り
先ほど解説したクライアントとサーバー間のやり取りを図で表すと、次のようになります。
- クライアント:サーバーに要求を送る
- サーバー:クライアントに処理結果を応答
これはよくある解説ですが、これだけだと具体的に何が行われているかがイメージできないため、さらに処理を分解してみましょう。
- クライアント:要求メッセージを構築
- クライアント:要求メッセージをサーバーに送信(応答がくるまで待機)
- サーバー:要求メッセージを受信
- サーバー:要求メッセージを解析
- サーバー:アプリケーションプログラムにて処理
- サーバー:応答メッセージを構築
- サーバー:応答メッセージをクライアントに送信
- クライアント:応答メッセージを受信
- クライアント:応答メッセージを解析
- クライアント:適切な処理を行う(画面描画など)
クライアントでは要求メッセージを、サーバーでは応答メッセージを構築し、それらを送受信してやり取りをしていることがわかります。
HTTPでは、要求メッセージをHTTPリクエスト、応答メッセージをHTTPレスポンスと呼びます。
HTTPリクエストとHTTPレスポンスは、どのようなWebサイトにアクセスする場合でも必ず発生します。のちほど、ChromeのDevToolsを使って実際のデータを見てみますが、まずはそれぞれの構造を理解しましょう。
HTTPリクエスト
クライアントからサーバーに要求を送る役割のHTTPリクエストメッセージは、次のような構造となっています。
例えば、CodeGridのトップページを要求するリクエストメッセージは、次のようになります(ヘッダーは一部のみ抜粋)。
GET / HTTP/1.1
Host: app.codegrid.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) ...
それではリクエストメッセージの意味をひとつひとつ見ていきましょう。
リクエストライン
1行目はリクエストラインです。サーバーに要求する情報で、メソッド、リクエストURI、プロトコルバージョンで構成されます。
GET / HTTP/1.1
これを日本語にするなら、「HTTPのバージョン1.1で通信を行い、/というURIに対して、情報の取得(GET)をリクエストします。」となります。
HTMLの表示や画像の取得など、通常のリクエストはGETメソッドで行われます。メソッドには、GET、POST、PUT、DELETEなど8種類ありますが、よく使われるのはGETとPOSTです。これについては、次回以降に解説します。
ヘッダー
2行目以降は、ヘッダーです。HTTPリクエストメッセージに関する情報をサーバーに伝える役目をする記述が続きます。
Host: app.codegrid.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) ...
ヘッダーは『名前: 値』の組み合わせで構成され、1つのメッセージに複数のヘッダーを持つことができます。
先ほどのリクエストラインのURIには「/」という情報しかありませんでしたが、このヘッダーのホスト情報と併せて、http://app.codegrid.net/
を示すことができます。
それ以外には、User agentや遷移元のURI(リファラ)、Cookieといったクライアントの情報などが含まれます。
空行
空行はヘッダーの終わりを意味します。
メッセージボディ
メッセージボディは、サーバーに送信するデータを格納する場所です。
HTMLや画像の取得のためのHTTPリクエストでは、サーバーにデータを送信する必要がないため、メッセージボディは空となります。先ほどの例でもメッセージボディは空です。
なお、HTMLのform要素もsubmit
によってHTTPリクエストを発行できます。メソッドをPOST
にした場合は、フォームに入力したテキストやチェックボックスなどの値は、メッセージボディに格納され、サーバーに送信されます。サーバー側では受信したHTTPリクエストのメッセージボディから値を解析して処理をします。
HTTPレスポンス
サーバーから結果を返す役割のHTTPレスポンスメッセージは、次のような構造となっています。
例えば、CodeGridのトップページのHTMLを返すレスポンスメッセージは、次のようになります(ヘッダーとメッセージボディは一部のみ抜粋)。
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Thu, 27 Nov 2014 11:36:47 GMT
<!DOCTYPE html>
<html lang="ja" data-env="prod" data-runapp>
...
</html>
ステータス行
1行目はステータス行です。サーバーでの処理結果を伝える情報で、プロトコルバージョン、ステータスコード、テキストフレーズで構成されます。
HTTP/1.1 200 OK
ステータスコードは3桁の数字で構成され、テキストフレーズはその内容を説明するテキスト情報です。
成功時は200 OK
となり、リクエストが正常に受理され、要求通りのレスポンスが返されたことを意味します。そのほかよく遭遇するものには404 Not Found
、500 Internal Server Error
などがあります*。
*注:そのほかのステータスコード
そのほかのステータスコードはRFC 7231の6 Response Status Codesにて、それぞれの仕様の現状がわかります。
サーバーは、処理に失敗したときもエラーの情報をレスポンスとして返します。つまり、クライアントからリクエストを送信したら、必ずそれに対する何かしらのレスポンスを受信することになります。
ヘッダー
2行目以降はヘッダーです。HTTPレスポンスメッセージに関する情報をクライアントに伝えるための記述が続きます。
Content-Type: text/html; charset=utf-8
Date: Thu, 27 Nov 2014 11:36:47 GMT
ヘッダーにはメッセージボディのタイプや文字コード、サイズ、メッセージを生成した日付といったレスポンスするデータの情報や、サーバーのソフトウェア情報などが含まれます。
コラム:HTMLのmeta要素
HTMLのhead
タグ内に、次のような記述をしたことはないでしょうか。
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
これは、レスポンスヘッダーに次の指定をしているのと同じことになります。
Content-Type: text/html; charset=utf-8
http-equiv
がヘッダーの名前、content
がヘッダーの値に該当します。
つまり、これまでHTTPの仕組みを意識せずに書いていたmeta要素のhttp-equiv
というのは、実はHTTPレスポンスのヘッダーを指定するのと同じだったというわけです。
なお、現在のHTML5の仕様では、meta要素に指定できるhttp-equiv
の値は、次の5種類のみとなっています。
content-language
content-type
default-style
refresh
set-cookie
メッセージボディ
メッセージボディは、クライアントに送信するHTMLや画像などのデータを格納する場所です。
<!DOCTYPE html>
<html lang="ja" data-env="prod" data-runapp>
...
</html>
例えば、Webページを表示するリクエストに対するレスポンスの場合、HTMLのソースコードがそのままここに格納されます。
HTTPリクエストとHTTPレスポンスを確認
HTTPリクエストとHTTPレスポンスは、ChromeのDevToolsでも見ることができます。実際に確認してみましょう。
- ChromeのDevToolsを表示し、Networkタブを開く
- 確認したいWebページを表示(この例では、CodeGridのトップページ)
- HTMLや画像、CSS、JSファイルなどのレスポンスの一覧が表示される
- 該当するレスポンス(この例ではHTML)をクリックして詳細を表示
(大きな画像)
Headersタブの上部に、リクエストラインとステータスラインの情報やアドレス情報などが集約され、その下のRequest HeadersとResponse Headersに各ヘッダーの情報が表示されます。
ヘッダーの情報は、Chromeによってパースされた状態で表示されています。パースされていない生の状態を見るには、view sourceをクリックすると、スタートラインとヘッダーが表示されます。
HTTPレスポンスのメッセージボディは、Responseタブで確認できます。
この例にはありませんが、HTTPリクエストのメッセージボディがある通信であれば、Headersタブに項目が追加されます。
AjaxでのHTTPリクエストやHTTPレスポンスも同じようにDevToolsで確認できます。このように実際にやり取りされているデータを確認することで、開発時に、正しい値が送信されているかなどをチェックできます。
同期と非同期
クライアントとサーバー間のやり取りにおいて、次のような注意書きがあったことに気が付いたでしょうか。
クライアント:要求メッセージをサーバーに送信(応答がくるまで待機)
クライアントは、HTTPリクエストを送ったあと、HTTPレスポンスがサーバーから返ってくるまで、ずっと待機することになります。ネットワークが遅い場合に、ページが真っ白になることがありますが、あの状態です。この間、ユーザーは何もできません。
このように、リクエストを送ってからレスポンスが返ってくるまでの間、ほかの処理を行わずにレスポンスを待ち続ける通信方式のことを同期と言います。
しかし、Ajaxなら非同期で通信を行うことが可能です。非同期では、リクエストを送ったあと、いったん放置して別の作業を進めておき、レスポンスが返ってきたタイミングで、そのあとの処理を再開します。
そのため、ユーザーは待つというストレスを感じることなく、ほかの作業を進めることができます。また、ページ全体の動作をストップさせることなく、ページの一部のみを更新するといったことも可能となります。これがAjaxのメリットです。
次回はいよいよ、このAjaxの仕組みについて掘り下げていきます。