HTTP 基本と特徴

# はじめに
こんにちは。

今回は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`を採用しています。

私たちが常に利用しているウェブブラウザからも下記のようにプロトコルの情報を確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/9524d6d8-8b4e-251a-0aa9-3d65444bd9e0.png)

qiitaでは**HTTP/ 1.1**と**HTTP/ 2**プロトコルを使って通信していることが分かります。
ここで、**h2**は**HTTP/ 2**を意味します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/902dddd2-4fe9-293d-1616-2523d224ccb0.png)
また、Googleでは**h3**つまり**HTTP/ 3**を使っていることが確認できます。

# HTTPの特徴
次は**HTTP**の特徴について調べていきます。
> - Client - Server 構造
> - Stateless and Connectionless
> - HTTP Message
> - Simplicity and Extensibilty

## client - server 構造

**HTTP**は基本的に**Client** - **Server**構造になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/167de968-95a9-75f0-5ca4-b5b226389dec.png)

クライアントはサーバーに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」はいくらですか？
・店員１：10万円です。　
> 
> ・御客さん：「2つ」購入します。
・店員２：？何を2つ購入しますか？
> 
> ・御客さん：「クレジット」でお願いします。
・店員３：？何をいくつ、クレジットで購入しますか？

上記の会話は**Stateful**な環境で、会話ごとに店員が変わる場合の例です。

各店員は前の会話を分からないため、お客さんの最終的な要求事項について理解していない状況です。
お客さんの要求（`PC`、`2つ`、`クレジットカード`）について店員ごと知っているのが違うからです。

つまり、**Stateful**な設計の**デメリット**は**一つのクライアントが複数のサーバーと通信する**場合、リクエストに対して、**各サーバーで保持している状態が異なる**ため、クライアントの要求に正確なレスポンスを返すことはできなくなります。

### stateless

では、状態を保持しない**Stateless**はどうでしょうか？

次は**Stateless**な状態での会話の例です。
>・御客さん：この「PC」はいくらですか？
・店員１：10万円です。　
> 
> ・御客さん：「PC」を「2つ」購入します。
・店員２：PC、2つは20万円です。お支払いは「クレジット」と「現金」中どっちにしますか？
> 
> ・御客さん：「PC」を「2つ」購入します。「クレジット」でお願いします。
・店員３：20万円、支払い完了しました。

**Stateless**はサーバーがクライアントの状態を保持していません。そのため、クライアントは**会話ごとに自分が必要な要求事項を伝える**必要があります。

不自然だと思われるかもしれませんが、こうすることで、途中でサーバーが変わってもクライアントの要求事項にあった対応ができます。

また、お客さんが増えても店員を増やせることで、対応ができるようになります。
これは、クライアントの通信量が増えてもサーバーの増設が可能となります。


### statelessのメリット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/b8f6a7a3-48fb-182e-a4b8-78c3abed1e48.png)


**stateful**な状態でクライアントとサーバー間の通信中、エラーが発生すると、今まで保持していた情報をすべて失われるようになります。

そうなると、クライアントは同じリクエストをほかのサーバーと通信しないといけません。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/616ab2d8-5310-7220-2d0c-c33a073818ab.png)
一方、**Stateless**な状態ではサーバーでクライアントの状態を保持していなくて、**クライアント側で必要な情報をすべてサーバー側に送っている**ため、**他のサーバーが対応**することができます。

こういう設計は、スケールアウト（Scale Out）にもいい設計になります。

### statelessの限界

もちろん、すべてのサービスを**Stateless**な状態で設計することは難しいです。

例えば、**ログインが要らない単なるサービスの紹介画面**がいれば、**ユーザーのログイン情報が必要な画面**もいるはずです。

ログインが必要な画面については、ユーザーのログイン情報をサーバー側で保持する必要があります。
このように、サーバーでクライアントの状態を保持する必要がある場合は、**ブラウザのクッキーとセッション**を利用し、状態を保持することもできます。

しかし、サーバーでエラーが発生すると、セッションなどの情報が失われる可能性もあります。

2つ目で、**クライアントが送るデータの量が多くなる**問題もあります。

前の例でもわかる通り、サーバーが状態を保持していないため、クライアントは自分の要求事項に必要な情報をすべて伝えることで、データを量が多くなりかねません。

このような限界があるにも関わらず、**stateless**には色んなメリットがあるため、
**stateless**な設計が推奨されています。

やむを得ずサーバーで状態を保持する必要がある場合は、サーバーは最小限の状態を保持するように設計した方がいいです。

## Connectionless
次の特徴は**コネクションレス型**（Connectionless）です。

コネクションレス型とは、データ通信時に、データをやりとりする**端末間でお互いにコネクション（接続関係）を設定しない**接続形態のことを言います。

では、**コネクション型**モデルと**コネクションレス型**モデルを次の画像を見て、説明します。

### コネクション型モデル

まず、コネクション型モデルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/6e2863bd-6a50-fabf-76c7-51fa640d2207.png)

上記の画像のようにクライアントとサーバー間のコネクションを維持する例としては、**TCP/IP**があります。

画像を見るとクライアントは3台があります。各クライアントはサーバーと通信した後も、コネクションを維持していることが分かります。
こうなると、サーバーは**通信もしていないクライアントとのコネクションを維持する**ため、**リソースを使い続けている*はずです。

### コネクションレス型モデル
すると、コネクションレス型モデルはどのような仕組みなのでしょうか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/99a8e4ae-1b09-bc04-d57e-7a148a097d92.png)

上記の画像のように、サーバーは**クライアントとリクエストがある場合**だけ、クライアントと**コネクションを行い、通信が終わればコネクションを切ります。**
こうすることで、最小限のリソースでHTTP通信を行うことができます。

まとめると、`HTTP`は基本的に**コネクションレス型のモデル**であることです。それによってクライアントは**HTTP通信を行い場合だけ、サーバーとのコネクションを維持し、サーバーが最小限のリソースで通信ができる**ようになります。




# HTTP メッセージ

最後に、HTTPのメッセージの構造について調べていきます。

この記事では、詳細については説明しません。

まず、HTTPのメッセージの全体的な構造を次の画像で確認してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/3ea3bc59-dd9e-9ec4-6f9e-67099970aab1.png)

HTTPメッセージは`start-line`、`header`、`empty line`、`message body`４つで分かれています。
この中で、`empty line`は空白ラインで必須となります。

HTTPの全体的な構造は同一ですが、**リクエスト**と**レスポンス**ごと、
<font color="red">**構造する要素は異なります。**</font>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/f9400086-ec46-663a-e254-ae855b5dd8af.png)


### 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
<html>
    <body>...<body>
<html>
```

上記の例では、リクエストの場合、Bodyは省略されていて、レスポンスのBodyだけHTMLデータが含まれていることを確認できます。

これは、クライアントがGETメソッドを利用したので、それに対するレスポンスをすることだと考えられます。

# おわりに
最後まで、ご覧いただけありがとうございます。

この記事では、HTTPの概念、特徴を調べてきました。

HTTPはWEBエンジニアにとって欠かせない、基本知識の一つだと思い、
ゼロから勉強をし直しています。

まだ、勉強することがたくさん残っているので、毎日勉強しながら、セクションごと記事を書こうと思います。

# 参考サイト
https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC