HTTP通信の中身

HTTP通信を何気なーく使っている皆さん。
HTTP`Hypertext Transfer Protocol (HTTP/1.1)`ってどのようなプロトコルかご存知でしょうか。

そんな疑問を少しでも解消すべく、軽く説明しようかなと思います。
なんとなくわかったつもりになって記事を書いているので間違っている箇所があればご指摘をお願い致します。

# 概要

とは言っても、RFCのように規約内容ををダラダラ書いても意味がわからないと思うので、実践を踏まえて全体の流れを見ていきたいと思います。

# 通信の流れ

HTTP通信はあるサーバ（オリジンサーバ）とクライアント（ユーザエージェント）間で行われる通信を規約化されたものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116536/110daf2e-63ef-619b-ddca-44f1a9b438ad.png)

HTTPの規約があることで、クライアントとサーバ間でのテキストのやり取りが可能になります。
これを大前提に、一度通信内容を見てみましょう。
 
# 通信の中身を見てみよう

Windowsの方はWSLでUbuntuなど入れて試してみましょう。
https://qiita.com/Brutus/items/f26af71d3cc6f50d1640

## オリジンサーバの設定

まずはサーバ側のセッティングを行います。
なんでもいいのですが、今回は`npm`の`http-server`を使います。

> Linux Ubuntu

```bash
$ sudo apt install -y nodejs npm
```

> MacOS

```bash
$ brew install node
```


> 共通

```bash
$ sudo npm install -g http-server
$ mkdir test_program
$ cd test_program
$ vim index.html

# index.htmlを編集

$ http-server ./
Starting up http-server, serving ./
Available on:
  http://127.0.0.1:8080
Hit CTRL-C to stop the server
```

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>Document</title>
</head>
<body>
</body>
</html>
```

これでHTTPサーバの起動は完了です。（超簡単）

# 通信の内容を見よう！

さて、HTTP通信の内容を見てみよう。

サーバを起動しつつ、別のターミナルで`curl`というコマンドを叩いてみると通信の内容が全て見られます。

```bash
$ curl -v "http://127.0.0.1:8080"
```

## 通信内容

```
* Rebuilt URL to: http://127.0.0.1:8080/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< server: ecstatic-3.3.1
< cache-control: max-age=3600
< last-modified: Sat, 27 Apr 2019 14:08:58 GMT
< etag: W/"3068562-99-2019-04-27T14:08:58.104Z"
< content-length: 99
< content-type: text/html; charset=UTF-8
< Date: Sat, 27 Apr 2019 14:10:45 GMT
< Connection: keep-alive
<
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>Document</title>
</head>
<body>
</body>
</html>
* Connection #0 to host 127.0.0.1 left intact
```

## 各所解説

### コネクション
```
* Rebuilt URL to: http://127.0.0.1:8080/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
```

こちらは`curl`が行っているTCP/IPプロトコルによるコネクションの確率を意味しています。
こちらはTCP/IPプロトコルの話なので、割愛します。


### リクエスト（要求）

```
> GET / HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
```

ここから本題です。

この通信内容はクライアントからサーバへのリクエスト内容を示しています。

HTTP通信は、文字列を規則的に送信することで解釈を行っています。
したがって、規則的に送信をしなかった場合はサーバ側でHTTP通信とみなされなくなり、エラーを排出（あるいは解釈不能による予期せぬ挙動）します。

```
GET / HTTP/1.1
メソッド名 URI 規格/メジャーバージョン.マイナーバージョン
```

メソッド名のあと、**スペースが一つ入り**、その後にURL...
など、スペースの場所もすべて該当します。

では、ここからはサクッと見てまいりましょう。

||解説|
|:-:|:-:|
|`GET / HTTP/1.1`|`GET` というメソット名で、リクエストしたURLは `/` 規格は `HTTP/1.1`|
|`Host`| 接続先が `127.0.0.1:8080` ということを意味しています |
|`User-Agent`| 今回は`curl`を使用しましたので、ユーザエージェントは`curl`となっています|
|`Accept`|例えばテキストのみであれば `text/plain` 画像であれば `image/jpeg`となります|
|最後の空白|これがないとリクエストが終了したことがわかりません。最後はなにもない行を投げます。|


### レスポンス（返答）

```
< HTTP/1.1 200 OK
< server: ecstatic-3.3.1
< cache-control: max-age=3600
< last-modified: Sat, 27 Apr 2019 14:08:58 GMT
< etag: W/"3068562-99-2019-04-27T14:08:58.104Z"
< content-length: 99
< content-type: text/html; charset=UTF-8
< Date: Sat, 27 Apr 2019 14:10:45 GMT
< Connection: keep-alive
<
```

||解説|
|:-:|:-:|
|`HTTP/1.1 200 OK`|プロトコル了解しましたという意味です。　ステータスコードは正常である２００番でメッセージの最後にOKがあります。|
|`server` | サーバの名前です|
|`cache-control`|キャッシュの情報をリクエスト、レスポンスの双方で共有するために記述しています|
|`last-modified`|最後にキャッシュがリセットされた時刻です|
|`etag`|バリアントのエンティティタグ|
|`content-length`|コンテンツのデータ量です|
|`content-type`|`html`ファイルであったり、文字コードを指定しています|
|`Date`|レスポンス時の時刻です|
|`Connection`|ホップバイホップヘッダ|


### コンテンツデータ

```
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>Document</title>
</head>
<body>
</body>
</html>
```

先程記述したデータが帰ってきて、通信終了です。

# 最後に

いかがでしたでしょうか。
普段使用しているWebブラウザからのリクエストやレスポンスはこのようなテキストのやり取りで行われているんですね。
それを応用して様々な通信を行っていたりします（Websocketなどなど）

興味があればRFCを読めば完全に理解できると思いますので、是非そちらをご観覧ください。
https://triple-underscore.github.io/RFC2616-ja.htm

ではでは。