httpについて

httpは、HyperText Transfer Protocolの略で、Web上で情報をやり取りするためのプロトコルです。 主にWebブラウザとWebサーバー間で使用され、リクエストとレスポンスの形式でデータを送受信します。

ここでは基本となる、HTTP 1.0での通信の流れで見ておきましょう。 このバージョンでは、1回のリクエストとレスポンスのやりとりが完了すると通信が終了するという特徴があります。

graph LR; A[Webブラウザ] -- リクエスト --> B[Webサーバー]; B -- レスポンス --> A;

httpにおいては、リクエストとレスポンスが本来1往復で終わるという構造になっています。そしてそのやりとりが完了すると切断されるという構造となっており、次に繋げたとしてもそれは新規の通信という扱いになっています。

注釈

佐藤は勝手に 一期一会方式 と称しています。 間違ってはいないと思いますが、あくまで個人の見解です。

注釈

HTTP 1.1において、持続的な接続(Keep-Alive)が標準化されたため、同じサーバーへのリクエストについては一度作成したコネクションをそのまま続けて使うことも可能になっています。これにより接続・切断へのオーバーヘッドが低減される見込みがあります。

HTTPのステートレス性

HTTPの最も重要な特徴の一つが ステートレス(stateless) であることです。これは、サーバーが過去のリクエストについての情報を保持しないということを意味します。

ステートレスとは

ステートレスプロトコルでは、各リクエストは独立しており、サーバーは以前のリクエストのことを「覚えて」いません。つまり、クライアントが送信する各リクエストには、サーバーがそのリクエストを処理するために必要な情報がすべて含まれている必要があります。

sequenceDiagram participant C as クライアント participant S as サーバー C->>S: リクエスト1 (ログイン) S->>C: レスポンス1 (成功) Note over S: サーバーはログイン状態を覚えていない C->>S: リクエスト2 (ページ表示) S->>C: レスポンス2 (認証が必要です)

一期一会方式の具体例

例えば、あるWebサイトにログインしたとします。従来の電話回線のような ステートフル な通信であれば、一度ログインすればその通信セッションが続く限り、サーバーは「この人はログイン済み」ということを覚えています。

しかし、HTTPでは:

  1. 最初のリクエスト: 「ログインします(ユーザー名: 田中、パスワード: 123456)」

  2. サーバーからのレスポンス: 「ログイン成功!」

  3. 通信終了・切断

  4. 次のリクエスト: 「マイページを見せてください」

  5. サーバーからのレスポンス: 「あなたは誰ですか? ログインしてください」

このように、サーバーは2回目のリクエスト時には1回目のログイン情報を覚えていません。

HTTPメッセージの基本構造

HTTPの通信は、リクエストレスポンスの2つのメッセージで構成されます。

HTTPリクエストの構造

HTTPリクエストは以下の要素で構成されます:

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36

  1. リクエスト行: メソッド、URL、HTTPバージョン

  2. ヘッダー: 追加情報(Host、User-Agentなど)

  3. 空行: ヘッダーとボディの区切り

  4. ボディ: データ(GETの場合は通常空)

HTTPレスポンスの構造

HTTPレスポンスは以下の要素で構成されます:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1024

<!DOCTYPE html>
<html>
<head><title>例</title></head>
<body><h1>こんにちは</h1></body>
</html>
  1. ステータス行: HTTPバージョン、ステータスコード、理由句

  2. ヘッダー: 追加情報(Content-Type、Content-Lengthなど)

  3. 空行: ヘッダーとボディの区切り

  4. ボディ: 実際のデータ(HTMLファイルなど)

基本的な通信フロー

sequenceDiagram participant C as クライアント participant S as サーバー Note over C: リクエスト作成 C->>S: HTTP リクエスト Note over S: リクエスト処理 S->>C: HTTP レスポンス Note over C: レスポンス処理 Note over C,S: 通信終了(切断)

このフローが完了すると、通信は終了し、次の通信は全く新しい通信として扱われます。

ステートレス性の利点と欠点

利点

  1. シンプルさ: サーバーが状態を管理する必要がないため、システム設計が単純になります。

  2. スケーラビリティ: どのサーバーでもリクエストを処理できるため、負荷分散が容易です。

    graph TD A[クライアント] --> B[ロードバランサー] B --> C[サーバー1] B --> D[サーバー2] B --> E[サーバー3] Note1[どのサーバーでも同じように処理可能]
  3. 信頼性: サーバーがクラッシュしても、状態情報が失われることがありません(そもそも保持していないため)。

  4. キャッシュ効率: 同じリクエストに対しては同じレスポンスが返されるため、中間のプロキシやブラウザでキャッシュしやすくなります。

欠点

  1. 認証情報の再送信: 毎回認証情報を送信する必要があるため、セキュリティ上のリスクが高まる可能性があります。

  2. パフォーマンスの低下: 毎回すべての情報を送信するため、通信量が増加する場合があります。

  3. ユーザー体験の制限: ログイン状態やショッピングカートの内容など、継続的な状態を保持することが困難です。

現実的な解決策

実際のWebアプリケーションでは、以下の方法でステートレス性の欠点を補完しています、これらの技術については、別の章で詳しく解説します。

  • Cookie: クライアント側に状態情報を保存

  • セッション: サーバー側で状態を管理(セッションIDをCookieで管理)

  • JWT(JSON Web Token): 認証情報をトークンに含めて送信

具体例: ステートレスな通信の実演

例1: Webページの閲覧

通常のWebページを閲覧する際の通信を見てみましょう:

# 1回目の通信
クライアント → サーバー: GET /news.html HTTP/1.1
サーバー → クライアント: HTTP/1.1 200 OK (news.htmlの内容)
[通信終了]

# 2回目の通信(別のページへ)
クライアント → サーバー: GET /sports.html HTTP/1.1  
サーバー → クライアント: HTTP/1.1 200 OK (sports.htmlの内容)
[通信終了]

各通信は完全に独立しており、サーバーは前回何を送ったかを覚えていません。

例2: ログインが必要なページ(問題のケース)

# 1回目: ログイン
クライアント → サーバー: POST /login HTTP/1.1
                        Content-Type: application/x-www-form-urlencoded
                        
                        username=tanaka&password=123456
                        
サーバー → クライアント: HTTP/1.1 200 OK
                       <html>ログイン成功!</html>
[通信終了]

# 2回目: マイページアクセス
クライアント → サーバー: GET /mypage.html HTTP/1.1

サーバー → クライアント: HTTP/1.1 401 Unauthorized 
                       <html>ログインが必要です</html>

この例では、1回目でログインに成功したにも関わらず、2回目のリクエストでは認証エラーになってしまいます。

まとめ

HTTPの「一期一会方式」(ステートレス性)は:

  • 各通信が独立している

  • サーバーは前回の通信を覚えていない

  • シンプルスケーラブルな設計を可能にする

  • 一方で、継続的な状態管理が困難

  • Cookieセッションなどの技術で補完される

この基本原理を理解することが、Web技術全体を理解する第一歩となります。