HTTP (Hyper Text Transfer Protocol) はWebにおいてクライアントとサーバーとの一連のやり取りの流れを決めているプロトコル。
まずはじめにTCP/IP
インターネットで一般的に使われているネットワークはTCP/IPというプロトコル群で動いていて、HTTPもそのうちの1つ。
TCP/IPは4つの階層に分かれている。
アプリケーション層 | ユーザーに提供するアプリケーションで使う通信の動きを決める。 FTP, DNS, HTTP など。 |
トランスポート層 | アプリケーション層に対してネットワークで接続されている2台のコンピューター間の流れを提供する。 TCP, UDP |
ネットワーク層 (インターネット層) | ネットワーク上のパケットの輸送を扱う。パケットは通信するデータの最小単位。 どのような経路を経て相手までパケットを送るかを決める。 |
リンク層 (データリンク層) | ネットワークに接続するハードウェア的な面を扱う。OSがハードウェアを制御するためのデバイスドライバなど。 その他、ケーブルなどの物理的に見える部分も含む。 |
TCP
TCP(Transfer Control Protocol)はトランスポート層にあたり、信頼性のあるバイト・ストリーム・サービスを提供する。大きなデータをTCPセグメントと呼ばれる単位のパケットに分割し、確実に相手に届ける。
確実に相手に届けるためにスリーウェイハンドシェイク方式をとっている。簡単にいうと、相手にパケットを送った後、受け取った連絡がなければ同じパケットを再送する仕組み。
- 送信側が SYN パケットを送信する。
- 受信側は SYN パケットを受け取ったら SYN/ACK パケットを送信側に送り、パケットを受け取ったことを伝える
- 最後に、送信側は ACK パケットを送り、受信側にやり取りが完了したことを伝える
IP
IP(Internet Protocol)はネットワーク層にあたる。インターネットプロトコル(IP)は、データパケットがネットワークを経由して正しい宛先に到達できるように、パケットをルーティングおよびアドレス指定するためのプロトコル。このときに重要になってくるのがIPアドレスとMACアドレス。
同じLAN内ではイーサネットがパケットの配送を担当する、このとき最終的な宛先のIPアドレスと中継先のルータのMACアドレスをパケットに付けて送る。MACアドレスをもとにルータにパケットが到達すると、次にルータは宛先のIPアドレスから次に中継する先のMACアドレスを調べて送る(ARPを使って調べる)。これをバケツリレーのように繰り返していき、最終目的地まで運んでいく。
役割分担のイメージ:同一ネットワーク内で配送するときにはMACアドレスを使い、ネットワークをまたぐときにはIPアドレスを使う。
HTTP/1.1とは
HTTP/1.1, HTTP/2.0, HTTP/3.0 では事情が異なるため、HTTP/1.1 をベースに解説。
リソース要望と返答が、メッセージ単位で、1往復のクライアントリクエスト&サーバーレスポンスという形で通信されるという通信方法を定めたプロトコル。
HTTPはTCPコネクションを利用して通信している。

HTTP はステートレス
HTTPは状態を保持しないステートレスなプロトコル。一つ前のリクエスト/レスポンスは覚えていない。多くの処理を確実に素早く処理するためにシンプルな設計になっている。
ただし、HTTP1.1からログイン状態など状態を保持できるようにCookieが導入された。
サーバーからのレスポンスのSetCookieというヘッダーフィールドによってクライアントにCookieを保存してもらう。それ以降クライアントは、同じサーバーにリクエストするときにはCookieをリクエストヘッダーに付けて送信する。
持続的接続
HTTPの初期バージョンでは、HTTP通信を行うたびにTCPによる接続と切断を行う必要があった。しかし、HTTP/1.1から持続的接続(Persistent Connections)が導入された。これはどちらかが明示的に接続を切断しない限り、TCP接続を繋げっぱなしにするということ。TCPコネクションの接続と切断を繰り返すオーバーヘッドが無くなり、サーバーに対する負荷軽減され、Webページの表示速度も向上した

パイプライン化
持続的接続によって複数リクエストを発行できるパイプライン化も可能になった。レスポンスを待たずに複数のリクエストを送ることができるので、個別に送るよりもリクエスト完了が速くなる。
しかし、リクエストを送った順にレスポンスを受け取る必要がある。前のリクエストのレスポンスが返ってくるのに時間がかかれば、後続のレスポンスも待たされてしまう。
HTTPの弱点
- 通信が平文なので盗聴可能
- 通信相手を確かめないのでなりすまし可能
- リクエスト/レスポンス先が本来意図したサーバー/クライアントなのかわからない
- 完全性を証明できないので改竄可能
- 完全性を証明できないので改竄可能
通信内容は平文で送られる。TCP/IPの仕組みとして通信の内容はすべての通信経路の途中で覗き見できる。インターネットは世界中を経由するネットワークでできているため、通信経路上にあるケットワーク機器やケーブル、コンピューター全てが自分の物であることはない。悪意を持った誰かが覗き見る可能性がある。
そのため、個人情報などをHTTPで平文でやり取りすると全部筒抜け。Wiresharkというツールやtcpdumpを使えば同一ネットワークの通信なら簡単に盗聴できちゃう。
この弱点補うためにTLS(SSL)を使うHTTPS通信を利用する。
HTTP/3.0 ではTLS利用前提になっているのでHTTP/1.1, 2.0の弱点といった方が正確なのかもしれない
HTTP/2.0
HTTP/1.1 でパイプライン化に対応したが、リクエストした順にレスポンスを返すという制約があった。レスポンスに時間がかかると後続のレスポンスも待たされる。(Head-of-Line-Blocking)
これを解消するためにHTTP/2.0では、1つのTCPコネクション上で複数のHTTPメッセージを並列的に多重化してやりとりできるようになった。HTTPリクエスト/レスポンスのペアはストリームという単位で管理される。ストリームの仕組みによりリクエストを送った順番でレスポンスを返すという制約がなくなり、HTTPのHead-of-Line-Blockingは解消された。ストリームは独立しており、パケットロスなどの問題が出ない限りは他のストリームに影響しない。つまり、あるストリームの処理に時間がかかっても、別のストリームの応答を返せる。

ストリームはあくまでも管理の単位。実際にデータをネットワーク上で送信する際は並列ではない。
HTTPメッセージをフレームという単位に分割してそれを直列で送っている。
また、リクエストされていないコンテンツをサーバーがクライアントに送信する「サーバープッシュ」機能が追加された。これはクライアントが「index.html」をリクエストしてきたときに、それに続いて(どうせこの後リクエストされるであろう)cssやjsなどをサーバーからクライアントに送信可能という仕組み。こうすることでクライアントがリクエストを行うオーバーヘッドを削減できる。
その他にも、HTTPヘッダー圧縮やテキストベースで行われていた通信がバイナリベースに変わったり、さまざまな最適化・高速化が行われた。
HTTP/2.0の課題
一番大きな問題はTCPのHead-of-Line-Blocking
HTTPが下位層で利用しているTCPは「パケットロス」や「パケットの順番の入れ替わり」が発生した場合、パケットの再送やもとの順番に戻して問題を解消する必要がある。そして、解消されるまで処理は待ちとなる。
つまり、先に送信されていたストリームのデータ送信の際にパケットロスなどの問題が発生した場合、後続のストリームのデータのパケットを受信できても、パケットロスが解消されるまでブラウザは処理を進めることができない。これをTCPのHead-of-Line-Blockingという。
先程「パケットロスなどの問題が出ない限りは他のストリームに影響しない」と書いたのはこういうこと。
HTTP/3.0
HTTP/2.0の課題を解消するために、HTTP/3.0ではトランスポート層にTCPではなくQUICという新しいプロトコルが採用された。QUICはパケットロスや順番の入れ替わりが発生しても受信側が受け取った順番通りにデータを処理できるため、処理待ちが発生しない。

QUICは暗号化通信(SSL証明書の利用)を前提としているため、TLSハンドシェイクが発生する。QUICではTLS1.3が利用されているため、TLS1.2以前と比較してTLSハンドシェイクで発生するやり取りが1往復減っている。また、TCPとTLSを利用する時はTCPコネクションを確立してからTLSハンドシェイクを行うが、QUICではそれらのやりとりをまとめて行う。その分、効率化されている、。
QUICの特徴
- 下位層にUDPを使っているが、TCP同様に信頼性がある
- TLSのセキュリティが組み込まれているため、TLSの利用は必須。コネクション確立方法が効率化されている。
- パケットロスが発生しても受信側の処理が待たされない。(HTTP/2.0 のTCPのHead-of-Line-Blocking解消)
まとめ
- HTTP (Hyper Text Transfer Protocol) はWebにおいてクライアントとサーバーとの一連のやり取りの流れを決めているプロトコル。TCP/IPの4階層でいうアプリケーション層に該当する。
- HTTPはシンプルさゆえ、平文で通信するため盗聴可能、通信相手が意図通りか確認をしない、メッセージの改竄に気づかないといった弱点がある。これを補うためにHTTPS(HTTP over TLS/SSL)を使う。
- HTTP/2.0 まではTCPを利用、HTTP/3.0 からQUICを利用するようになった
- HTTP/1.1 でパイプライン化が可能になったがリクエストの順番通りにレスポンスを返す必要があり、後続レスポンスが待たされる課題があった
- HTTP/2.0 でストリームによる多重化が可能になったが、トランスポート層(TCP)でのHead-of-Line-Blockingは解決しなかった。パケットロスなどの問題が発生したとき、受け取り側がパケットを通し番号通りに組み立てる必要があり、処理待ちが発生するため。
- HTTP/3.0 ではUDPベースかつTLS利用を前提としたQUICという新しいプロトコルをトランスポート層に導入し、TCPのHead-of-Line-Blockingを解消した。QUICではパケットロスが発生しても受信側は受け取った順番で処理を進めれるので処理待ちが発生しない。
参考
YouTube ByteByteGo