HTTPプロトコルの理解：なぜこのように設計されたのか

[![Group5212.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/132515c2-2da6-43dd-bdea-8353a83cf9fc.png)](https://leapcell.io/?lc_t=q_http)


**[Leapcell：Webホスティング、非同期タスク、およびRedis用の次世代サーバレスプラットフォーム](https://leapcell.io/?lc_t=q_http)**

# HTTPプロトコル：インターネットの礎石とWeb開発に不可欠な知識

[![fetching-a-page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/870da1c6-d713-4dbf-8bfb-24af5d1aa1ec.png)](https://leapcell.io/?lc_t=q_http)


インターネットの世界において、HTTPプロトコルは間違いなく基本的なプロトコルであり、Web開発分野における不可欠な知識です。特に、その最新バージョンであるHTTP/2は広く注目を集め、技術的なホットスポットとなっています。この記事では、HTTPプロトコルの歴史的な進化と設計理念について深掘りし、読者にこの重要な技術について包括的な理解を得てもらうことを目的とします。

## I. HTTP/0.9：インターネット通信の萌芽形態
HTTPはTCP/IPプロトコルに基づくアプリケーション層プロトコルです。それは主にクライアントとサーバ間の通信形式を指定し、データパケットの送信には関係ありません。デフォルトではポート80を使用します。1991年にリリースされたHTTP/0.9バージョンは、HTTPプロトコルの最古のバージョンです。その設計は非常にシンプルで、GETという1つのコマンドのみがあります。

```
GET /index.html
```
上記のコマンドの意味は、TCP接続が確立された後、クライアントがサーバに対してindex.htmlというウェブページを要求することです。プロトコルによれば、サーバはHTML形式の文字列での応答のみが可能で、他の形式での応答はできません。例えば：
```html
<html>
  <body>Hello World</body>
</html>
```
サーバが送信を完了すると、直ちにTCP接続を閉じます。このバージョンはシンプルですが、HTTPプロトコルの後続の開発の基礎を築き、クライアントとサーバ間の単純な通信モードの確立を告げました。

## II. HTTP/1.0：機能の最初の拡張
1996年5月、HTTP/1.0バージョンがリリースされました。HTTP/0.9と比較して、その内容は大幅に増え、インターネットの開発に重要な変化をもたらしました。
### 2.1 概要
 - **コンテンツ形式の多様化**：HTTP/1.0では、任意の形式のコンテンツの送信が可能になりました。これにより、インターネットはもはやテキスト送信に限定されず、画像、ビデオ、バイナリファイルなどの様々な種類のデータがネットワークを通じて送信できるようになり、インターネットの多様化の発展に堅牢な基礎を築きました。
 - **豊富なインタラクティブコマンド**：GETコマンドに加えて、POSTコマンドとHEADコマンドが導入されました。POSTコマンドは、ユーザー登録やログイン時に送信される情報など、サーバにデータを送信するためによく使用されます。HEADコマンドは主に、実際のリソースコンテンツを返さずに、リソースのメタ情報を取得するために使用されます。これらのコマンドの追加により、ブラウザとサーバ間のインタラクション方法が大幅に豊富になりました。
 - **要求と応答形式の変更**：各通信において、データ部分に加えて、ヘッダ情報（HTTPヘッダ）が含まれなければなりません。これは、要求のソース、クライアントの種類、受け入れ可能なデータ形式などのメタデータを記述するために使用されます。また、ステータスコード（status code）、マルチ文字セットサポート、マルチパート送信（multi - part type）、認証、キャッシュ、コンテンツエンコーディングなどの機能が追加されました。ステータスコードは、サーバが要求に対する処理結果を示すために使用されます。例えば、200は要求が成功したことを示し、404はリソースが見つからなかったことを示します。マルチ文字セットサポートにより、インターネット上で異なる言語のコンテンツが正しく表示されるようになりました。キャッシュ機能により、繰り返しの要求を減らし、アクセス速度を向上させることができます。

### 2.2 要求形式

[![http-request.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/6e364015-8c2e-4523-a464-da41ebe91bea.png)](https://leapcell.io/?lc_t=q_http)


```
GET / HTTP/1.0
User - Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
```
HTTP/0.9バージョンと比較して、1.0バージョンの要求形式は大幅に変化しています。最初の行は要求コマンドで、末尾にはプロトコルバージョン（HTTP/1.0）が追加されなければなりません。以下は複数行のヘッダ情報で、クライアントの状況を記述するために使用されます。User - Agentフィールドはクライアントの種類とバージョンを識別し、Acceptフィールドはクライアントが受け入れることができるデータ形式を宣言します。

### 2.3 応答形式

[![http-response.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/a482747c-e029-478d-b61b-226c16f2ab51.png)](https://leapcell.io/?lc_t=q_http)


```
HTTP/1.0 200 OK 
Content - Type: text/plain
Content - Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last - Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84

<html>
  <body>Hello World</body>
</html>
```
サーバの応答形式は「ヘッダ情報 + 1行の空白（\r\n） + データ」です。このうち、最初の行は「プロトコルバージョン + ステータスコード（status code） + ステータス説明」です。ステータスコード200は要求が成功したことを示し、OKはステータス説明です。Content - Typeフィールドはデータの種類を示し、Content - Lengthフィールドはデータの長さを示し、Expiresフィールドはリソースの有効期限を指定し、Last - Modifiedフィールドはリソースの最終更新時刻を示し、Serverフィールドはサーバの種類とバージョンを識別します。

### 2.4 Content - Typeフィールド
HTTP/1.0バージョンでは、ヘッダ情報は必ずASCIIコードで、その後のデータは任意の形式であることができます。したがって、サーバが応答するとき、Content - Typeフィールドを通じてクライアントにデータの形式を伝える必要があります。Content - Typeフィールドの一般的な値は以下の通りです：
 - **テキストタイプ**：text/plain（プレーンテキスト）、text/html（HTMLドキュメント）、text/css（CSSスタイルシート）。
 - **画像タイプ**：image/jpeg（JPEG画像）、image/png（PNG画像）、image/svg + xml（SVGベクターグラフィック）。
 - **オーディオとビデオタイプ**：audio/mp4（MP4オーディオ）、video/mp4（MP4ビデオ）。
 - **アプリケーションタイプ**：application/javascript（JavaScriptスクリプト）、application/pdf（PDFドキュメント）、application/zip（ZIP圧縮ファイル）、application/atom + xml（Atom XMLドキュメント）。

これらのデータタイプはまとめてMIMEタイプと呼ばれます。各値は主なタイプとサブタイプを含み、スラッシュで区切られます。予め定義されたタイプに加えて、メーカーは独自のタイプも定義できます。例えば、`application/vnd.debian.binary - package`は、送信されるデータがDebianシステムのバイナリデータパッケージであることを示します。MIMEタイプはセミコロンを使用して末尾にパラメータを追加することもできます。例えば、`Content - Type: text/html; charset=utf - 8`は、送信されるデータがウェブページであり、エンコーディングがUTF - 8であることを示します。クライアントが要求を行うとき、受け入れることができるデータ形式をAcceptフィールドを使用して宣言することができます。例えば、`Accept: */*`は、クライアントが任意の形式のデータを受け入れることができることを示します。MIMEタイプはHTTPプロトコルだけでなく、他の分野でも広く適用されています。例えば、HTMLウェブページでは、`<meta http - equiv="Content - Type" content="text/html; charset=UTF - 8" />`または`<meta charset="utf - 8" />`を通じて、ページのエンコーディングとコンテンツタイプを指定することができます。

### 2.5 Content - Encodingフィールド
送信されるデータは任意の形式であることができるため、送信効率を向上させるために、データを送信前に圧縮することができます。Content - Encodingフィールドは、データの圧縮方法を示すために使用されます。一般的な値は`gzip`、`compress`、`deflate`です。クライアントが要求を行うとき、受け入れることができる圧縮方法をAccept - Encodingフィールドを使用して示します。例えば、`Accept - Encoding: gzip, deflate`です。

### 2.6 欠点
HTTP/1.0バージョンの主な欠点は、各TCP接続で1つの要求しか送信できないことです。データ送信後、接続は閉じられます。他のリソースを要求する必要がある場合は、新しい接続を確立する必要があります。新しいTCP接続を確立するコストは比較的高く、クライアントとサーバは3回のハンドシェイクを行う必要があり、初期の送信速度が遅い（スロースタート）ため、HTTP 1.0バージョンのパフォーマンスが低下します。ウェブページに読み込まれる外部リソースが増えるにつれ、この問題はますます顕著になりました。この問題を解決するため、一部のブラウザは要求に非標準のConnectionフィールドを使用しました：
```
Connection: keep - alive
```
このフィールドはサーバにTCP接続を閉じないように要求し、他の要求で再利用できるようにします。サーバもこのフィールドで応答する場合、再利用可能なTCP接続が確立され、クライアントまたはサーバが積極的に接続を閉じるまで維持されます。ただし、これは標準のフィールドではなく、異なる実装での動作が異なる可能性があるため、根本的な解決策ではありません。

## III. HTTP/1.1：幅広く使用される古典的なバージョン
1997年1月、HTTP/1.1バージョンがリリースされました。1.0バージョンからわずか半年後のことです。このバージョンはHTTPプロトコルをさらに改良し、今日でも幅広く使用されているバージョンとなりました。
### 3.1 永続接続
HTTP/1.1バージョンの最大の変化は、永続接続の導入です。つまり、TCP接続はデフォルトでは閉じられず、`Connection: keep - alive`を宣言する必要なく、複数の要求で再利用できます。クライアントとサーバは、相手がしばらく活動していないことを検出したときに、積極的に接続を閉じることができます。ただし、標準的な方法は、クライアントが最後の要求で `Connection: close` を送信し、サーバに対してTCP接続を明示的に閉じるように要求することです。現在、ほとんどのブラウザは同じドメイン名に対して6つの永続接続を確立できるようになっており、これによりHTTPプロトコルの効率が大幅に向上しています。

### 3.2 パイプライン化
HTTP/1.1バージョンはまた、パイプライン化メカニズムを導入しました。同じTCP接続内で、クライアントは複数の要求を同時に送信できます。たとえば、クライアントが2つのリソースを要求する必要がある場合、以前の方法では同じTCP接続内でまず要求Aを送信し、サーバの応答を待ってから、応答を受け取った後に要求Bを送信することでした。パイプライン化メカニズムにより、ブラウザは要求Aと要求Bを同時に送信できます。サーバは依然として順番に要求Aに最初に応答し、完了後に要求Bに応答しますが、この方法によりHTTPプロトコルの効率がさらに向上します。

### 3.3 Content - Lengthフィールド
HTTP/1.1バージョンでは、1つのTCP接続で複数の応答を送信できます。したがって、データパケットがどの応答に属するのかを区別するためのメカニズムが必要です。Content - Lengthフィールドの機能は、この応答内のデータの長さを宣言することです。たとえば：
```
Content - Length: 3495
```
この1行のコードは、ブラウザにこの応答の長さが3495バイトであり、その後のバイトは次の応答に属することを通知します。1.0バージョンでは、サーバがTCP接続を閉じるのをブラウザが検出すると、すべてのデータパケットが受信されたことを知るため、Content - Lengthフィールドは必須ではありませんでした。1.1バージョンでは、TCP接続が再利用可能になったため、異なる応答を区別するためにデータ長を明確にする必要があります。

### 3.4 チャンク転送エンコーディング
Content - Lengthフィールドを使用する前提は、サーバが応答を送信する前に応答データの長さを知っていることです。一部の時間のかかる動的操作の場合、これはサーバがすべての操作が完了するまで待ってからデータを送信しなければならないことを意味し、効率が低くなります。この問題を解決するため、HTTP/1.1バージョンでは、Content - Lengthフィールドを使用せず、代わりに「チャンク転送エンコーディング」を使用できることが規定されています。要求または応答ヘッダにTransfer - Encodingフィールドがある場合、それは応答が不定数のデータチャンクで構成されることを示します。たとえば：
```
Transfer - Encoding: chunked
```
各空でないデータチャンクの前には、このチャンクの長さを示す16進数値があります。最後に、サイズ0のチャンクは、この応答内のデータが完全に送信されたことを示します。以下は例です：
```
HTTP/1.1 200 OK
Content - Type: text/plain
Transfer - Encoding: chunked

25
This is the data in the first chunk

1C
and this is the second one

3
con

8
sequence

0
```
この方法により、サーバはデータが生成され次第送信でき、「バッファモード」を「ストリームモード」に置き換え、データ送信の効率を向上させます。

### 3.5 その他の機能
HTTP/1.1バージョンはまた、多くの動詞メソッドを追加しました。たとえば、PUT（リソースの更新に使用）、PATCH（リソースの部分的な更新に使用）、HEAD（GETに似ていますが、ヘッダ情報のみを返し、リソースコンテンツを返さない）、OPTIONS（サーバがサポートする要求メソッドなどの情報を取得するために使用）、DELETE（リソースの削除に使用）です。また、クライアント側の要求ヘッダにはHostフィールドが追加され、これはサーバのドメイン名を指定するために使用されます。たとえば：
```
Host: www.example.com
```
Hostフィールドを使用することで、同じサーバ上の異なるウェブサイトに要求を送信できるようになり、仮想ホストの台頭に基礎を築きました。Hostフィールドを通じて、サーバは異なるドメイン名に応じて異なるサービスを提供でき、リソースの共有と分離を実現します。

### 3.6 欠点
HTTP/1.1バージョンはTCP接続の再利用を可能にしていますが、同じTCP接続内ではすべてのデータ通信が順次行われます。サーバは1つの応答を完了した後、次の応答を処理します。前の応答が特に遅い場合、多くの要求がキューに入れられて待機することになり、これが「先頭ブロッキング（Head - of - line blocking）」と呼ばれます。この問題を回避するために、現在は2つの方法しかありません。1つは要求の数を減らすこと、もう1つは複数の永続接続を同時に開くことです。これにより、スクリプトとスタイルシートのマージ、CSSコード内への画像の埋め込み、ドメイン分割など、多くのウェブページ最適化技術が登場しました。ただし、HTTPプロトコルがもっと良く設計されていれば、これらの追加的な努力は不要であったでしょう。

## IV. SPDYプロトコル：HTTP/2の前身
2009年、Googleは独自開発のSPDYプロトコルを公開しました。主にHTTP/1.1の低効率な問題を解決することを目的としていました。Chromeブラウザで実行可能が証明された後、SPDYプロトコルはHTTP/2の基礎として使用され、その主な機能はHTTP/2に引き継がれました。SPDYプロトコルは、HTTPプロトコルの最適化、例えばヘッダ情報の圧縮や多重化を通じて、データ送信の効率を向上させ、HTTP/2の開発に貴重な経験と技術的な基礎を提供しました。

## V. HTTP/2：効率的な次世代プロトコル
2015年、HTTP/2がリリースされました。HTTP/2.0と呼ばれないのは、標準化委員会がもはやサブバージョンをリリースする予定がないためです。次の新しいバージョンはHTTP/3になります。HTTP/2はHTTPプロトコルの開発史上において非常に重要な地位を占め、一連の目覚ましい改良をもたらしました。
### 5.1 バイナリプロトコル
HTTP/1.1バージョンのヘッダ情報はテキスト（ASCIIエンコード）で、データ本体はテキストまたはバイナリであることができます。しかし、HTTP/2は完全なバイナリプロトコルです。ヘッダ情報とデータ本体の両方がバイナリで、「フレーム」と総称され、ヘッダフレームとデータフレームが含まれます。バイナリプロトコルの利点は、追加のフレームを定義できることです。HTTP/2は10近いフレームを定義しており、将来的な高度なアプリケーションのために良好な基礎を築いています。これらの機能をテキストを使用して実装する場合、データの解析は非常に面倒ですが、バイナリ解析の方がはるかに便利です。バイナリプロトコルは、より効率的にデータを送信および処理でき、プロトコルのパフォーマンスと柔軟性を向上させます。

### 5.2 多重化
HTTP/2はTCP接続を再利用します。1つの接続内で、クライアントとブラウザの両方が複数の要求または応答を同時に送信でき、順序を1対1で対応させる必要がありません。これにより、「先頭ブロッキング」を回避できます。たとえば、1つのTCP接続内で、サーバは要求Aと要求Bを同時に受け取ります。そのため、まず要求Aに応答します。処理プロセスが非常に時間のかかることがわかった場合、サーバは要求Aの既に処理された部分を送信し、次に要求Bに応答します。完了後、要求Aの残りの部分を送信します。この双方向でリアルタイムな通信が多重化と呼ばれます。多重化技術により、HTTP/2は同じ接続上で複数の要求と応答を同時に処理でき、送信効率を大幅に向上させます。

### 5.3 データストリーム
HTTP/2のデータパケットは順序なく送信されるため、同じ接続内の連続するデータパケットは異なる応答に属する可能性があります。したがって、データパケットにマークを付けて、どの応答に属するのかを示す必要があります。HTTP/2は各要求または応答のすべてのデータパケットをデータストリームと呼びます。各データストリームには一意の番号が付けられます。データパケットを送信するとき、それがどのデータストリームに属するのかを区別するために、データストリームIDを必ずマークする必要があります。また、クライアントが送信するデータストリームは奇数のIDを持ち、サーバが送信するデータストリームは偶数のIDを持つことが規定されています。データストリームが途中で送信されているとき、クライアントとサーバの両方が信号（RST_STREAMフレーム）を送信して、このデータストリームをキャンセルすることができます。HTTP/1.1バージョンでは、データストリームをキャンセルする唯一の方法はTCP接続を閉じることでした。しかし、HTTP/2では、特定の要求をキャンセルしながらも、TCP接続が依然として開いており、他の要求で使用できることを保証できます。クライアントはまた、データストリームの優先度を指定することもできます。優先度が高いほど、サーバは早く応答します。データストリームの概念と関連するメカニズムを通じて、HTTP/2はより柔軟かつ効率的なデータ送信と管理を実現します。

### 5.4 ヘッダ圧縮
HTTPプロトコルはステートレスで、すべての情報は各要求に添付する必要があります。したがって、要求内の多くのフィールドは繰り返されます。たとえば、CookieやUser - Agentです。同じコンテンツは各要求に添付する必要があり、これは多くの帯域幅を浪費し、速度に影響を与えます。HTTP/2は、ヘッダ圧縮メカニズムを導入することでこれを最適化しました。一方で、ヘッダ情報は送信前にgzipまたはcompressを使用して圧縮されます。もう一方で、クライアントとサーバの両方がヘッダ情報テーブルを保持します。すべてのフィールドはこのテーブルに格納され、インデックス番号が生成されます。 その後、同じフィールドは再送信されず、インデックス番号のみが送信されるため、速度が向上します。 ヘッダ圧縮メカニズムは、データ送信量を効果的に削減し、送信効率を向上させます。

### 5.5 サーバプッシュ
HTTP/2は、サーバが要求なしにクライアントに資源を積極的に送信できるようにしており、これをサーバプッシュと呼びます。 一般的なシナリオは、クライアントが多くの静的リソースを含むWebページを要求する場合です。通常、クライアントはWebページを受け取り、HTMLソースコードを解析し、静的リソースを発見してから、静的リソースに対する要求を送信する必要があります。 しかし、サーバは、クライアントがWebページを要求した後、おそらく静的リソースを要求すると予想できるため、Webページとともにこれらの静的リソースをクライアントに積極的に送信します。 サーバプッシュ技術は、クライアントの要求数を減らし、ユーザーエクスペリエンスを向上させます。

HTTPプロトコルの開発履歴は、継続的な進化と最適化のプロセスです。 最初は単純なHTTP/0.9から機能豊富なHTTP/1.1、そして効率的なHTTP/2まで、各バージョンは前のバージョンの問題に対処し、パフォーマンスと機能を強化してきました。 技術の絶え間ない発展に伴い、将来のHTTP/3も期待に値します。 なぜなら、それがインターネット通信技術の進歩を引き続き推進するからです。 

# [Leapcell：Webホスティング、非同期タスク、およびRedis用の次世代サーバレスプラットフォーム](https://leapcell.io/?lc_t=q_http)

最後に、Webサービスの展開に最適なプラットフォームをおすすめします：**[Leapcell](https://leapcell.io/?lc_t=q_http)**

[![barndpic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/7bbd7949-6d63-4a7c-8bec-8a796d9e48c5.png)](https://leapcell.io/?lc_t=q_http)


### 1. 多言語対応  
- JavaScript、Python、Go、またはRustで開発可能。  

### 2. 無制限のプロジェクトを無料で展開
- 使用量に応じてのみ課金 — 要求がなければ料金はかかりません。

### 3. 圧倒的なコスト効率  
- 使い捨て型で、アイドル時の料金はかかりません。  
- 例：25ドルで、平均応答時間60msで694万回の要求をサポート。  

### 4. 合理化された開発者体験  
- 直感的なUIによる簡単なセットアップ。  
- 完全自動化されたCI/CDパイプラインとGitOps統合。  
- アクション可能な洞察のためのリアルタイムメトリックとロギング。  

### 5. 簡単なスケーラビリティと高性能  
- 高い同時実行数を簡単に処理するための自動スケーリング。  
- オペレーションオーバーヘッドはゼロ — 構築に集中できます。  

[![Frame3-withpadding2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/d857ece6-92e3-4b1d-baa4-fe25c245374b.png)](https://leapcell.io/?lc_t=q_http)


[ドキュメントで詳細をご覧ください！](https://docs.leapcell.io/)

LeapcellのTwitter：[https://x.com/LeapcellHQ](https://x.com/LeapcellHQ)