はじめに
こんにちは。
今回はWEBエンジニアにとって欠かせない、HTTPについて記事を作成しようと思います。
HTTPについては、その内容が多いため、シリーズになりそうです。
では、自分が勉強したことをこれから皆さんに共有したいと思います。
HTTPとは
まずは、HTTPについて簡単に説明します。
HTTP(hyperText transfer protocol)
はHTMLで書かれた文書などの情報をやりとりする時に使われる通信手順(プロトコル)を意味します。
現在は、HTML
はもちろんTEXT
、IMAGE
、AUDIO
、VIDEO
、FILE
、からJSON
、XML
などのAPIまで、すべてのタイプのデータで通信ができます。
HTTPの歴史
✅ HTTP/ 0.9 (1991)
✅ HTTP/ 1.0 (1996)
✅ HTTP/ 1.1 (1997)
✅ HTTP/ 2 (2015)
✅ HTTP/ 3 (2015~)
HTTPは1991年に登場した通信プロトコルです。
初期にはバージョンとして管理されていなかったのですが、以降のバージョンと区分するためにHTTP/ 0.9と呼ばれたようです。この時代のHTTPはGETメソッドのみサポートされ、ヘッダーは定義されていない簡単な構造でした。
1996年になって色んなメソッドとヘッダーが追加されました。
現在、一番多く使われているHTTP/ 1.1は1997年に登場されました。通信に関するほとんどのSPECはHTTP/ 1.1バージョンに含まれているため、HTTPの記事で最も重要なバージョンです。
HTTP/ 2とHTTP/ 3は実際に使われてはいますが、HTTP/ 2とHTTP/ 3は性能を改善に目的があるため、HTTP/ 1.1が標準プロトコルで使われています。
また、HTTP/ 1.1とHTTP/ 2はTCP
の上で通信を行っていて、HTTP/ 3はUDP
を採用しています。
私たちが常に利用しているウェブブラウザからも下記のようにプロトコルの情報を確認することができます。
qiitaではHTTP/ 1.1とHTTP/ 2プロトコルを使って通信していることが分かります。
ここで、h2はHTTP/ 2を意味します。
また、Googleではh3つまりHTTP/ 3を使っていることが確認できます。
HTTPの特徴
次はHTTPの特徴について調べていきます。
- Client - Server 構造
- Stateless and Connectionless
- HTTP Message
- Simplicity and Extensibilty
client - server 構造
HTTPは基本的にClient - Server構造になっています。
クライアントはサーバーにHTTPでリクエストを送り、サーバーはクライアント側から送られたリクエストに対しての結果をレスポンスを送ります。
ここで、クライアントはサーバーからレスポンスが届くまで待機します。
このようにクライアントとサーバーで分けているのはHTTPの最も大事な特徴ですが、その理由はメンテナンスと、拡張性にあります。
クライアントとサーバーを分離すれば、ビジネスロジックやデータはサーバー側で管理し、クライアント側はUIやUXのようなユーザーに関する機能に集中できるようになります。
こうすることで、独立的に性能などを向上することができます。クライアントはデータに関する作業を行う必要がなくなり、サーバーもアーキテクチャや技術的なところに集中できます。
Stateful, stateless
次のHTTPの特徴はサーバーがクライアントの状態を保持しない点です。これをstatelessといいます。
逆に、サーバーがクライアントの状態を保持すればstatefulといいます。
stateful
まずstatefulについて簡単な例を見てみましょう。
・御客さん:この「PC」はいくらですか?
・店員:10万円です。
(PCの状態を保持)・御客さん:「2つ」購入します。
・店員:20万円です。お支払いは「クレジット」と「現金」中どっちにしますか?
(PC, 2つの状態を保持)・御客さん:「クレジット」でお願いします。
・店員:20万円、支払い完了しました。
(PC, 2つの状態を保持)
買い物をする際の、日常的な会話です。
お客さんは会話ごとに、自分の要求を伝えて、店員はお客さんの会話を覚えながら対応してます。
お客さんをクライアント、店員をサーバーと考えてみましょう。
サーバーは前の会話を覚えながら、それぞれの要求に対して対応をしています。そのため、クライアントは前の会話を繰り返すことなく、その場で必要な要求だけ伝えて済みます。
この会話でサーバーが保持しているデータはPC
、2つ
、クレジットカード
になるはずです。また、この状態を保持することで、自然な会話ができると思います。
しかし、Statefulな設計にも次のようなデメリットがあります。
・御客さん:この「PC」はいくらですか?
・店員1:10万円です。・御客さん:「2つ」購入します。
・店員2:?何を2つ購入しますか?・御客さん:「クレジット」でお願いします。
・店員3:?何をいくつ、クレジットで購入しますか?
上記の会話はStatefulな環境で、会話ごとに店員が変わる場合の例です。
各店員は前の会話を分からないため、お客さんの最終的な要求事項について理解していない状況です。
お客さんの要求(PC
、2つ
、クレジットカード
)について店員ごと知っているのが違うからです。
つまり、Statefulな設計のデメリットは一つのクライアントが複数のサーバーと通信する場合、リクエストに対して、各サーバーで保持している状態が異なるため、クライアントの要求に正確なレスポンスを返すことはできなくなります。
stateless
では、状態を保持しないStatelessはどうでしょうか?
次はStatelessな状態での会話の例です。
・御客さん:この「PC」はいくらですか?
・店員1:10万円です。・御客さん:「PC」を「2つ」購入します。
・店員2:PC、2つは20万円です。お支払いは「クレジット」と「現金」中どっちにしますか?・御客さん:「PC」を「2つ」購入します。「クレジット」でお願いします。
・店員3:20万円、支払い完了しました。
Statelessはサーバーがクライアントの状態を保持していません。そのため、クライアントは会話ごとに自分が必要な要求事項を伝える必要があります。
不自然だと思われるかもしれませんが、こうすることで、途中でサーバーが変わってもクライアントの要求事項にあった対応ができます。
また、お客さんが増えても店員を増やせることで、対応ができるようになります。
これは、クライアントの通信量が増えてもサーバーの増設が可能となります。
statelessのメリット
statefulな状態でクライアントとサーバー間の通信中、エラーが発生すると、今まで保持していた情報をすべて失われるようになります。
そうなると、クライアントは同じリクエストをほかのサーバーと通信しないといけません。
一方、Statelessな状態ではサーバーでクライアントの状態を保持していなくて、クライアント側で必要な情報をすべてサーバー側に送っているため、他のサーバーが対応することができます。
こういう設計は、スケールアウト(Scale Out)にもいい設計になります。
statelessの限界
もちろん、すべてのサービスをStatelessな状態で設計することは難しいです。
例えば、ログインが要らない単なるサービスの紹介画面がいれば、ユーザーのログイン情報が必要な画面もいるはずです。
ログインが必要な画面については、ユーザーのログイン情報をサーバー側で保持する必要があります。
このように、サーバーでクライアントの状態を保持する必要がある場合は、ブラウザのクッキーとセッションを利用し、状態を保持することもできます。
しかし、サーバーでエラーが発生すると、セッションなどの情報が失われる可能性もあります。
2つ目で、クライアントが送るデータの量が多くなる問題もあります。
前の例でもわかる通り、サーバーが状態を保持していないため、クライアントは自分の要求事項に必要な情報をすべて伝えることで、データを量が多くなりかねません。
このような限界があるにも関わらず、statelessには色んなメリットがあるため、
statelessな設計が推奨されています。
やむを得ずサーバーで状態を保持する必要がある場合は、サーバーは最小限の状態を保持するように設計した方がいいです。
Connectionless
次の特徴はコネクションレス型(Connectionless)です。
コネクションレス型とは、データ通信時に、データをやりとりする端末間でお互いにコネクション(接続関係)を設定しない接続形態のことを言います。
では、コネクション型モデルとコネクションレス型モデルを次の画像を見て、説明します。
コネクション型モデル
上記の画像のようにクライアントとサーバー間のコネクションを維持する例としては、TCP/IPがあります。
画像を見るとクライアントは3台があります。各クライアントはサーバーと通信した後も、コネクションを維持していることが分かります。
こうなると、サーバーは通信もしていないクライアントとのコネクションを維持するため、**リソースを使い続けている*はずです。
コネクションレス型モデル
すると、コネクションレス型モデルはどのような仕組みなのでしょうか?
上記の画像のように、サーバーはクライアントとリクエストがある場合だけ、クライアントとコネクションを行い、通信が終わればコネクションを切ります。
こうすることで、最小限のリソースでHTTP通信を行うことができます。
まとめると、HTTP
は基本的にコネクションレス型のモデルであることです。それによってクライアントはHTTP通信を行い場合だけ、サーバーとのコネクションを維持し、サーバーが最小限のリソースで通信ができるようになります。
HTTP メッセージ
最後に、HTTPのメッセージの構造について調べていきます。
この記事では、詳細については説明しません。
まず、HTTPのメッセージの全体的な構造を次の画像で確認してみましょう。
HTTPメッセージはstart-line
、header
、empty line
、message body
4つで分かれています。
この中で、empty line
は空白ラインで必須となります。
HTTPの全体的な構造は同一ですが、リクエストとレスポンスごと、
構造する要素は異なります。
start-line
まず、リクエストのstart-lineを説明します。
start-line = rquest-line / status-line
Request-line
=HTTP Method
+SP(空白)
+Request-Target
+SP
+HTTP-version
+CRLF
リクエストのstart-lineはRequest-lineと呼ばれます。
Request-line
はHTTP Method
とリクエストの対象のRequest-Target
、そして、HTTP-version
で構成されています。
SP
は空白を意味し、最後のCRLF
は改行を意味します。
GET /search?q=hello&hl=jo HTTP/1.1
上記の例ではHTTP Method
はGETのことで、
Request-Target
は(/search?q=hello&hl=jp)、最後に、HTTP/1.1がHTTP-version
になります。
次は、レスポンスのリクエストのstart-lineを説明します。
start-line = rquest-line / status-line
Status-line
=HTTP-version
+SP
+Status-Code
+SP
+Reason-Phrase
+CRLF
レスポンスのstart-lineはStatus-lineと呼ばれます。
Status-lineはHTTP-version
が最初に定義され、Status-Code
、Reason-Phrase
の順で構成されています。
もちろんSP
とCRLF
も同じように構成されています。
Status-code
とは、HTTPレスポンスに含まれるWebサーバーの処理結果を表現する3桁の数字のことを指します。
- 200:成功
- 400:クライアントエラー
- 500:サーバーエラー
Reason-Phrase
は人が理解できるStatus-codeの説明文となります。
HTTP/1.1 200 OK
上記の例では、それぞれHTTP/1.1がHTTP-version
、200がStatus-Code
、OKがReason-Phrase
を指すことが分かります。
HTTP header
headerにはHTTP通信に必要な情報が含まれています。
Bodyに関する情報から、Bodyのサイズ、圧縮、認証、リクエスト側のブラウザ情報、サーバーアプリケーションの情報、キャッシュ管理情報など、その要素はいろいろあります。
また、必要に応じては、任意の要素を追加することもできます。
基本的なheaderの構造は次のようです。
header
=field-name
+:
+OWS
+field-value
+OWS
ヘッダーに入れたいfield-name
を定義し、その次に:
を定義します。その後、field-value
を定義します。
一般的なkey-valueタイプを作成する方法と一緒です。
OWS
は空白のことを言います。
次は、実際のヘッダーの構造です。
HOST: www.google.com
Content-Type: text/html;charset=UTF-8
Content-Length: 3423
この記事では、基本的なheaderの構造と、通信に必要な色んなメタデータが含まれることを知っておけばいいです。
詳細については後の記事で説明します。
HTTP Body
http bodyには実際に伝えるデータが含まれます。
含まれるデータとしては、html以外もimage, video, jsonなど、byteで表現できるすべてのデータが対象になります。
<html>
<body>...<body>
<html>
上記の例では、リクエストの場合、Bodyは省略されていて、レスポンスのBodyだけHTMLデータが含まれていることを確認できます。
これは、クライアントがGETメソッドを利用したので、それに対するレスポンスをすることだと考えられます。
おわりに
最後まで、ご覧いただけありがとうございます。
この記事では、HTTPの概念、特徴を調べてきました。
HTTPはWEBエンジニアにとって欠かせない、基本知識の一つだと思い、
ゼロから勉強をし直しています。
まだ、勉強することがたくさん残っているので、毎日勉強しながら、セクションごと記事を書こうと思います。
参考サイト