3 分で読了 #networking #HTTP
このページの目次

HTTP/1.1

HTTP/1.1 の中核メカニズム——永続接続、パイプライン(理論上は優れているが実践では劣る)、チャンク転送エンコーディング、キャッシュネゴシエーション——が Web の20年間のトラフィックを支えてきた。ヘッド・オブ・ライン・ブロッキングと接続数の制限が、HTTP/2 のマルチプレクシングを直接生み出した。

概要

HTTP/1.1(1997-2014)は、Web の基盤となるリクエスト-レスポンスモデル、ステータスコード、キャッシュ制御、永続接続を定義しました。HTTP/2 および HTTP/3 はパフォーマンスにおいて大幅に優れていますが、HTTP/1.1 はすべての HTTP 実装が互換性を保つための基準であり続けています。すべての HTTP/2 接続は、HTTP/1.1 のアップグレードリクエストから始まります。メッセージ形式、チャンク転送、CORS(Cross-Origin Resource Sharing)のクロスオリジン制御、およびキャッシュのセマンティクスを理解することは、Web 開発の基礎となります。

メッセージ形式

HTTP-message = start-line *(header-field CRLF) CRLF [ message-body ]

Request:
  GET /api/v1/query?q=up HTTP/1.1
  Host: grafana.example.com
  Accept: application/json
  Accept-Encoding: gzip, br

Response:
  HTTP/1.1 200 OK
  Content-Type: application/json
  Content-Length: 42
  Cache-Control: max-age=3600

  {"status":"success"}

Status Code:
  1xx: 情報 (100 Continue, 101 Switching Protocols)
  2xx: 成功 (200 OK, 201 Created, 204 No Content, 206 Partial Content)
  3xx: リダイレクト (301 Moved Permanently, 302 Found, 304 Not Modified, 307/308 redirect with method preserved)
  4xx: クライアントエラー (400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests)
  5xx: サーバーエラー (500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout)

永続接続

HTTP/1.0: 各リクエストごとに新しい TCP 接続を作成 → 3ウェイハンドシェイクのオーバーヘッド HTTP/1.1: Connection: keep-alive (デフォルト) — 1つの TCP 接続を再利用して複数のリクエストを送信

パイプライン (HTTP/1.1): 前のレスポンスを待たずに、複数のリクエストを連続して送信。実際にはほとんど使用されない(サーバーは順序通りに返信する必要があるため → HOL ブロッキング、プロキシとの互換性が低い)。

チャンク転送エンコーディング

レスポンスボディのサイズがヘッダーで事前にわからない場合(動的生成、ストリーミングデータなど):

HTTP/1.1 200 OK
Transfer-Encoding: chunked

1a\r\n
abcdefghijklmnopqrstuvwxyz\r\n
0d\r\n
Hello, World\r\n
0\r\n
\r\n

形式: <16進数で表したチャンクサイズ>\r\n<チャンクデータ>\r\n
最後のチャンク: 0\r\n + オプションのトレーラーヘッダー + \r\n

CORS

ブラウザの同一生成元ポリシー(same-origin policy)は、ページが異なるオリジンのリソースにアクセスすることを防ぎます。CORS はサーバーが例外を宣言することを許可します:

Simple Request (GET with simple headers):
  GET /api/data HTTP/1.1
  Origin: https://chat.example.com           ← ブラウザが自動追加

  HTTP/1.1 200 OK
  Access-Control-Allow-Origin: https://chat.example.com
  Vary: Origin

Preflight (before non-simple requests):
  OPTIONS /api/data HTTP/1.1
  Origin: https://chat.example.com
  Access-Control-Request-Method: POST
  Access-Control-Request-Headers: Content-Type

  HTTP/1.1 204 No Content
  Access-Control-Allow-Origin: https://chat.example.com
  Access-Control-Allow-Methods: GET, POST, PUT
  Access-Control-Allow-Headers: Content-Type
  Access-Control-Max-Age: 86400             ← preflight を24時間キャッシュ

Credentials (cookies, HTTP auth):
  Access-Control-Allow-Credentials: true     ← ワイルドカードオリジン "*" と併用不可
  Access-Control-Allow-Origin: https://chat.example.com  ← 具体的な値である必要がある

HTTP キャッシュ

Request:
  Cache-Control: max-age=3600                 ← 3600秒以内はフレッシュであることを期待
  If-None-Match: "abc123"                     ← 条件付きリクエスト (ETag)
  If-Modified-Since: Tue, 01 Jan 2025 00:00:00 GMT

Response:
  Cache-Control: public, max-age=86400, immutable
    public:        CDN/中間プロキシがキャッシュ可能
    private:       ブラウザのみがキャッシュ可能 (Authorization または cookie を含む場合)
    max-age:       フレッシュ期間 (レスポンスの日付から開始)
    immutable:     リソース内容が不変 (フィンガープリント付きアセット) → 再検証しない
    no-cache:      キャッシュを使用できるが、まず再検証する必要がある (If-None-Match)
    no-store:      いかなるキャッシュも保存しない (プライベートキャッシュを含む)
    must-revalidate: 期限切れ後は再検証が必要 (max-stale があっても)
  ETag: "abc123"                               ← リソースのバージョン (コンテンツハッシュ)
  Last-Modified: Tue, 01 Jan 2025 00:00:00 GMT

304 Not Modified:
  条件付きリクエスト If-None-Match が一致 → サーバーは 304 を返す (ボディは空) → クライアントはキャッシュを継続使用

参考

  • RFC: 7230-7235, 7234
  • MDN: developer.mozilla.org/en-US/docs/Web/HTTP

キーワード: HTTP/1.1, keep-alive, chunked, CORS, preflight, cache-control, ETag, conditional request