HTTP - HTTPメッセージ
概要
HTTPは、HTML文書等のリソースを取得するためのプロトコルである。
これは、Web上のあらゆるデータ交換の基礎であり、クライアントサーバプロトコルである。
つまり、リクエストは受信者(通常はWebブラウザ)によって開始される。
例えば、テキスト、レイアウト記述、画像、動画、スクリプト等、フェッチされた様々なサブドキュメントから完全なドキュメントが再構築される。
クライアントとサーバは、(データのストリームとは対照的に)個々のメッセージを交換することによって通信する。
クライアント(通常はWebブラウザ)が送信するメッセージはリクエストと呼ばれ、サーバが回答として送るメッセージはレスポンスと呼ばれる。
1990年代初頭に設計されたHTTPは、時代とともに進化してきた拡張可能なプロトコルである。
TCP、または、TLSで暗号化されたTCP接続で送信されるアプリケーション層プロトコルであるが、理論的には信頼性の高いトランスポートプロトコルであれば何でも使用できる。
その拡張性により、ハイパーテキストドキュメントだけでなく、画像や動画を取り込んだり、HTMLフォームの結果のようにコンテンツをサーバに投稿したりするのにも使用される。
また、HTTPはオンデマンドでWebページを更新するために、文書の一部をフェッチするのにも使用される。
HTTPの基本
単純な構造
HTTP/2のような、HTTPメッセージをフレームにカプセル化することにより複雑さが加わったとしても、HTTPは一般的にシンプルで人間が読めるように設計されている。
HTTPメッセージは人間が読んで理解することができ、開発者にとってはテストが容易になる。
拡張可能性
HTTP/1.0で導入されたHTTPヘッダは、このプロトコルの拡張を容易にする。
クライアントとサーバが新しいヘッダのセマンティクスについて合意するだけで、新しい機能を導入することもできる。
HTTPはステートレス、かつ、非セッションレス
HTTPはステートレス (HTTPリクエスト / HTTPレスポンスを1度送受信するごとに接続を切ることをステートレス型と呼ぶ) である。
同じコネクション上で連続して実行される2つのリクエストの間にはリンクがない。
例えば、eコマースのショッピングバスケットを使用する場合、特定のページと首尾一貫してやりとりしようとするユーザにとって問題となる見込みがある。
しかし、HTTPのコア自体はステートレスであるが、HTTPクッキーはステートフルなセッションの使用を可能にする。
ヘッダの拡張性を使用して、HTTPクッキーはワークフローに追加されて、各HTTPリクエストで同じコンテキスト、つまり、同じ状態を共有するセッション生成を可能にする。
HTTPとコネクション
コネクションはトランスポート層で制御されるため、基本的にHTTPの範囲外である。
HTTPは基礎となるトランスポートプロトコルがコネクションベースであることを要求しているわけではない。
インターネット上で最も一般的な2つのトランスポートプロトコルの内、TCPは信頼性があり、UDPは信頼性がない。
したがって、HTTPは、コネクションベースであるTCP標準に依存している。
クライアントとサーバがHTTPリクエスト / レスポンスのペアを交換する前に、TCPコネクションを確立する必要がある。
HTTP/1.0のデフォルトの動作は、HTTPリクエスト / レスポンスのペアごとに別々のTCPコネクションをオープンすることである。
これは、複数のリクエストが連続して送信される場合、1つのTCPコネクションを共有するよりも効率が悪い。
この欠陥を軽減するために、HTTP/1.1ではパイプライン化(実装が難しいことが判明)と持続的接続が導入された。
基礎となるTCP接続は、Connectionヘッダを使用して部分的に制御できる。
HTTP/2はさらに一歩進み、単一のコネクション上でメッセージを多重化することにより、コネクションをより効率的にする。
現在では、HTTPにより適したトランスポートプロトコルを設計するための実験が進行中である。
例えば、GoogleはUDPをベースに、より信頼性が高く効率的なトランスポートプロトコルを提供するQUICの実験を行っている。
HTTPで制御できること
HTTPのこの拡張可能な性質は、時代とともに、Webの制御と機能性の向上を可能にしてきた。
キャッシュや認証方法は、HTTPの歴史の初期に扱われていた機能である。
対照的に、オリジン制約を緩和する機能は、2010年代に追加された。
HTTPで制御可能な一般的な機能を、以下に示す。
- キャッシュ
- ドキュメントをどのようにキャッシュするかは、HTTPで制御できる。
- サーバはプロキシやクライアントに、何をどれくらいの期間キャッシュするかを指示することができる。
- クライアントは中間キャッシュプロキシに、保存されたドキュメントを無視するように指示できる。
- オリジン制約の緩和
- 盗聴やその他のプライバシー侵害を防ぐため、WebブラウザはWebサイト間の厳格な分離を強制している。
- 同じオリジンからのページのみが、Webページの全ての情報にアクセスできる。
- このような制約はサーバにとって負担であるが、HTTPヘッダは、サーバ側でこの厳密な分離を緩和することができ、ドキュメントが異なるドメインからの情報のパッチワークになることを可能にする。
- 認証
- ページによっては、特定のユーザのみがアクセスできるように保護されている場合がある。
- BASIC認証は、WWW-Authenticateや同様のヘッダを使用する、または、HTTPクッキーを使用して特定のセッションを設定することにより、HTTPによって提供される場合がある。
- プロキシとトンネリング
- サーバやクライアントは、ほとんどの場合はイントラネット上にあり、他のコンピュータから本来のIPアドレスを隠している。
- そして、HTTPリクエストは、このネットワークの障壁を越えるためにプロキシを経由する。
- また、全てのプロキシがHTTPプロキシというわけではない。
- 例えば、SOCKSプロトコルは、より低いレベルで動作する。
- FTPのような他のプロトコルは、これらのプロキシで処理することができる。
- セッション
- HTTPクッキーを使うことにより、リクエストとサーバの状態を結びつけることができる。
- 基本的なHTTPは、ステートのないプロトコルであるにもかかわらず、セッションを作成する。
- これは、eコマースのショッピングのみでなく、ユーザによる出力の設定を可能にするあらゆるサイトに役立つ。
HTTPの流れ
クライアントがサーバ (最終サーバ、または、中間プロキシ) と通信する場合、以下のような手順で実行される。
- TCPコネクションを開く。
- TCPコネクションは、リクエストを送信して、その回答 (レスポンス) を受信するために使用される。
- クライアントは、新しいコネクションを開いたり、既存のコネクションを再利用したり、サーバへの複数のTCPコネクションを開いたりすることができる。
- HTTPリクエストを送信する。
- HTTPメッセージ (HTTP/2以前) は人間が読むことができる。
- HTTP/2では、これらの単純なメッセージはフレームにカプセル化され、直接読むことは不可能であるが、原理は変化していない。
GET / HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr
- WebサーバがHTTPリクエストに対応する処理を行う。
- Webサーバから送信されたレスポンスを読む。
クライアント端末は、取得したhtmlファイルを確認して、CSSや画像ファイルが必要な場合は再度Webサーバにリクエストを送信する。HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
Server: Apache
Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
ETag: "51142bc1-7449-479b075b2891b"
Accept-Ranges: bytes
Content-Length: 29769
Content-Type: text/html
<!DOCTYPE html>… (here come the 29769 bytes of the requested web page)
- 接続を閉じる、または、次のリクエストのために再利用する。
HTTPパイプラインを有効にする時、最初のレスポンスが完全に受信されるのを待たずに、複数のリクエストを送信することができる。
HTTPパイプラインは、古いソフトウェアが最新バージョンと共存している既存のネットワークでは実装が難しいことが判明している。
HTTPパイプラインは、HTTP/2において、フレーム内でリクエストを多重化する、より堅牢なものに取って代わった。
HTTPメッセージ
HTTP/1.1以前で定義されたHTTPメッセージは、人間が読むことができる。
HTTP/2では、これらのメッセージはフレームというバイナリ構造に埋め込まれ、ヘッダの圧縮や多重化などの最適化が可能になる。
元のHTTPメッセージの一部のみがHTTP/2で送信されたとしても、各メッセージのセマンティクスは変更されず、クライアントは元のHTTP/1.1リクエストを (仮想的に) 再構成する。
したがって、HTTP/1.1形式でHTTP/2メッセージを理解することは有用である。
HTTPメッセージには、HTTPリクエストとHTTPレスポンスの2種類があり、それぞれ独自の書式をもつ。
HTTPリクエストの構成
HTTPリクエストは、以下の要素で構成される。
POST /submit HTTP/1.1 # リクエスト行 Host: example.com # ヘッダフィールド Content-Type: application/json # ヘッダフィールド Content-Length: 38 # ヘッダフィールド # 空行 {"username": "john", "age": 30} # メッセージボディ
リクエスト行
メソッド、URI、HTTPバージョンを含む。
- HTTPメソッド
- GET、POST、DELETE、OPTIONS、HEADがあり、クライアントが実行する操作を定義する。
- 例えば、クライアントがリソースをフェッチする場合 (GET)、または、HTMLフォームの値をポストする場合 (POST) 等がある。
- フェッチするリソースのパス
- コンテキストからプロトコル (http://)、ドメイン (developer.mozilla.org)、TCPポート番号 (80番等) を取り除いたリソースのURLである。
- HTTPプロトコルのバージョン
# 例 GET /index.html HTTP/1.1
ヘッダフィールド
リクエストの追加情報を含む。
- サーバに追加情報を伝えるオプションのヘッダ
- POSTのようないくつかのメソッドでは、送信されたリソースを含むレスポンスと似たボディ
# 例 Host: www.example.com User-Agent: Mozilla/5.0 Accept: text/html
空行
単純な改行であるが、ヘッダフィールドとメッセージボディを区切る重要な要素である。
メッセージボディ
主に、POSTリクエスト等でデータを送信する時にパラメータが記述される。
GETリクエストの場合は、空になることが多い。
# 例 (POSTパラメータ) {"username": "john", "age": 30}
HTTPレスポンスの構成
HTTPレスポンスは4つの主要な部分から構成されており、各部分が明確な役割を持つ。
特にヘッダフィールドは、クライアントがレスポンスを適切に処理するための重要な情報を提供する。
# HTTPレスポンスの例 HTTP/1.1 200 OK # ステータス行 Date: Thu, 14 Nov 2024 12:00:00 GMT # ヘッダフィールド Server: Apache/2.4.41 (Unix) # ヘッダフィールド Content-Type: text/html; charset=UTF-8 # ヘッダフィールド Content-Length: 138 # ヘッダフィールド # 空行 <!DOCTYPE html> # ボディ <html> <head> <title>Example Page</title> </head> <body> <h1>Hello, World!</h1> </body> </html>
ステータス行
- HTTPプロトコルのバージョン
- ステータスコード (HTTPリクエストが成功の可否、および、その理由が記載)
- ステータスメッセージ、ステータスコードの非正規の短い説明
下表に、主なHTTPレスポンスのステータスコードの一覧を示す。
- 1xx
- 情報
- 2xx
- 正常 (成功)
- 3xx
- リダイレクト関連
- 4xx
- クライアント側のエラー
- 5xx
- サーバ側のエラー
ステータスコード | 説明 |
---|---|
200 | OK リクエストが成功して、レスポンスが返されたことを示す。 |
301 | Moved Parmanently 指定したリソースは移動したため、新しい場所から取得することを示す。 例えば、Webサイトが恒久的に移転した場合は、この値を設定する。 |
302 | Moved Temporarily 指定したリソースは移動したため、新しい場所から取得することを示す。 例えば、Webサイトが一時的に移転した場合は、この値を設定する。 |
304 | Not Modified 指定したファイルは変更されていないため、Webブラウザのキャッシュを表示する。 |
401 | Unauthorixed 認証に失敗したことを示す。 |
403 | Forbidden アクセス権限が無いことを示す。 |
404 | Not Found リクエストしたアドレスのページが存在しないことを示す。 |
500 | Internal Server Error Webサーバにおいて、内部エラーが発生していることを示す。 |
502 | Bad Gateway ゲートウェイが無効なレスポンスを受信したことを示す。 |
503 | Service Unavailable サービスが提供できないことを示す。 例えば、Webサーバに負荷が掛かりすぎた場合等に表示される。 |
504 | Gateway Timeout 上流からのレスポンスが所定時間内に得られない場合に表示される。 |
ヘッダフィールド
レスポンスに関する各種メタ情報がある。
- HTTPリクエストと同様のHTTPヘッダ
- オプションとして、取得したリソースを含むボディ
# 例 Date: Thu, 14 Nov 2024 12:00:00 GMT Server: Apache/2.4.41 (Unix) Content-Type: text/html; charset=UTF-8 Content-Length: 138 Cache-Control: no-cache
主要なヘッダフィールドの役割を以下に示す。
- Content-Type
- メッセージボディのデータ形式を指定
- Content-Length
- メッセージボディのサイズ (バイト)
- Cache-Control
- キャッシュの動作を制御
- Set-Cookie
- クライアントにCookieを設定
- Location
- リダイレクト先のURLを指定 (3xxステータスで使用)
空行
単純な改行であるが、ヘッダフィールドとメッセージボディを区切る必須要素である。
メッセージボディ
- レスポンスの実際のコンテンツ (HTMLファイルの内容、JSON、画像データ等)
- Content-Typeヘッダで形式を指定する。
HTTPベースのAPI
HTTPをベースにしたAPIで最もよく使用されるものは、Fetch APIである。
これは、JavaScriptからHTTPリクエストを行うことができる。
Fetch APIは、XMLHttpRequest APIを置き換えるものである。
もう1つのAPIであるサーバ送信イベントは、HTTPをトランスポートメカニズムとして使用して、サーバがクライアントにイベントを送信できる一方向のサービスである。
EventSourceインタフェースを使用して、クライアントは接続を開き、イベントハンドラを確立する。
クライアントブラウザ (Webブラウザ) は、HTTPストリーム上に到着したメッセージを自動的に適切なEventオブジェクトに変換する。
そして、既知の場合はイベントのタイプに対して登録されているイベントハンドラに、タイプ固有のイベント・ハンドラが確立されていない場合はonmessageイベントハンドラに、それらを配信する。
POSTとPUTの違い
POST (作成・追加)
主に、新しいリソースを作成するために使用する。
クライアントはサーバにデータを送信して、サーバはそれを受信して新しいリソースを作成する。
同じデータを複数回送信しても、常に新しいリソースが作成される。
PUT (更新・置換)
既存のリソースを更新するために使用する。
クライアントはサーバに更新するリソースを送信して、サーバはそのデータで既存のリソースを置き換える。
PUTメソッドは、同じデータを複数回送信しても常に同じ結果が得られるように設計されている。
安全性
- POST
- 通常、POSTリクエストは安全ではないと見なされる。
- つまり、同じリクエストを繰り返しても同じ結果が得られない可能性がある。
- PUT
- PUTリクエストは一般的に安全であると見なされる。
- 同じPUTリクエストを複数回送信しても、常に同じ結果が得られるからである。
冪等性
- POST
- 通常、POSTは冪等ではない。
- 同じリクエストを繰り返しても、異なる結果が得られる可能性がある。
- PUT
- PUTは冪等である。
- 同じPUTリクエストを複数回送信しても、常に同じ結果が得られる。
POST
は、新しいリソースの作成に使用され、PUT
は既存のリソースの更新に使用される。
PUT
は冪等性があり、同じリクエストを複数回送信しても同じ結果が得られるため、更新操作に適している。