よく見るStatus Codeをまとめてみた

## 目的
これを読んだ人はどうなるのか？

- Status Codeとは何なのか知ることができる。
- Status Codeを見て、それが意味することをすぐに察することができるようになる。

## 対象
この記事を読んでほしい人

- Status Codeが何なのか知らない人。
- Web技術に興味を持ち始めた人。
- Railsでよく出てくる「200」「302」「404」「500」とかを知らない人。


## この記事を書いた経緯
この記事を書いている時点で、新卒入社一ヶ月ぐらいです。入社してからエンジニア研修を受けることになり、その過程で「ステータスコードが何を意味しているか言える。もしくは調べられる。」というお題があります。
このお題について説明しないといけないのですが、説明する=言語化するなので、この言語化したものを世に公開したほうがメリット大きくね？？？と思い、記事を書こうと思います。

## 注意事項
**ところどころ、私の解釈が入っています。基本的にはMDNやRFCを一部抜粋して訳したものです。誤った内容がある可能性があるため、100%鵜呑みにはしないようにしてください。**

では、早速書いていきます。

##What is Status Code?
まず、HTTPレスポンスの構成について知らない人は[HTTPリクエスト/レスポンスの構成要素を初心者にも分かるように解説してみた](https://qiita.com/koheiyamaguchi0203/items/5777c4653a01ae4c7b06)を読んでもらいたいです。
なぜなら、Status CodeはHTTPレスポンスの構成要素の一つである「Status Line」に含まれているものです。
このようなことが分からない中でStatus Codeについて学ぶのは非効率だと思います。なので、まずはHTTPリクエストやレスポンスについて知った方が良いのでは？と思います。

前置きと宣伝はこれくらいにして、本題に入ります。

Status Codeとは「リクエストをサーバが理解しようとした試みの結果を3桁の整数で表したもの」です。

具体的なものを見てみましょう。

```shell
curl --http1.1 --get -v https://example.com
```
上のコマンドを打つとこのような表示が見られます。

```
(略)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Thu, 25 Apr 2019 09:28:47 GMT
< Etag: "1541025663+gzip+ident"
< Expires: Thu, 02 May 2019 09:28:47 GMT
< Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
< Server: ECS (oxr/830C)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 1270
< 
(HTMLが返ってくる)
```
この「HTTP/1.1 **200** OK」とありますが、この**200**がStatus Codeです。このStatus Codeは５つのクラスに分類されています。Status Codeの一桁目は1~5の整数を取ります。その1~5毎に意味が与えられています。ここではそれぞれの意味を[RFC2616](https://tools.ietf.org/html/rfc2616#page-39)や[W3](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)、[Mozilla](https://developer.mozilla.org/)を頼りに書いていきます。

### 1xx(Informatial)

リクエストを受け取り、さらに処理を続けます。みたいなことがRFCには書いてあったはずなのですが、これだけを書いても何を言っているのか分からないので、具体的に1xxに属するStatus Codeを見てみましょう。

- 100(Continue)<br>
クライアントがサーバに対してリクエストを送る前にリクエストヘッダーに「Expect: 100-continue」というものを含んだリクエストを送ります。そうすると、100をStatus Codeとしたレスポンスが返ってきます。
どうしてクライアントは今述べたようなリクエストを送るのか？というと、サーバはとある条件のもとでリクエストのBodyを見ずにリクエストを破棄することがあるからです。とある条件とは具体的に言うと、とても重たいデータ(4K動画1時間とか？)を送るときなどが想定されます。
こうなると、最初からサーバにクライアントが送ろうとしているとても重たいデータをサーバが処理してくれるのかどうか？をクライアントはリクエストを送信する前に知っておきたいです。
そのために、最初に書いた「リクエストヘッダーに『Expect: 100-continue』というものを含んだリクエスト」を送ります。具体的なリクエストを[mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect)から引用します。

```
PUT /somewhere/fun HTTP/1.1
Host: origin.example.com
Content-Type: video/h264
Content-Length: 1234567890987
Expect: 100-continue

```

このように「Content-Length: Bodyに含まれるデータのバイト数」と「Expect: 100-continue」というリクエストヘッダーを含んだリクエストを送ります。
このリクエストヘッダー(Content-Lengthの値)をサーバは読み込み、サーバが処理できるのかどうか？を決めて、処理できるのであれば、Status Code 100を含んだレスポンスを返します。
このレスポンスを受け取り、読み込んだクライアントは続けて実際にデータが入ったリクエストを送ります。

このように100が存在する理由としては「サーバにクライアントが今からこのようなリクエストを送ろうと思っているが、サーバは処理できるのかどうかを聞かれて、その返しとして100を含んだレスポンスを返している。」ということです。で、100を受け取ったクライアントは実際にBodyを含んだリクエストを送ります。

ちなみに、サーバが100を返さない場合、つまり、サーバが処理できないと判断した場合に返すStatus Codeは417(Expectation Failed)です。これはサーバがリクエストのExpectリクエストヘッダーの値の期待に答えることができない場合に返されるStatus Codeです。

今回であれば、クライアントは100をStatus Codeとして期待している、つまり、続けてBodyの入ったリクエストを送って良いという許可を求めているが、サーバがそれを許可しないということを表しているStatus Codeが417だと言えそうです。

- 101(Switching Protocol)<br>
クライアントがサーバに対してプロトコルを切り替えてほしいという依頼し、その依頼が成功したことを表すために101を含んだHTTPレスポンスが返されます。
もっと具体的に述べます。
101(Switching Protocol)はサーバが```Upgrade```リクエストヘッダーを含んだリクエストを送ったクライアントによって依頼されたプロトコルに切り替えたことを示しています。このレスポンスにはサーバは```Upgrade```レスポンスヘッダーをレスポンスに含んでいます。```Upgrade```レスポンスヘッダーはサーバが切り替えたプロトコルを示すために使われます。[RFC6455](https://tools.ietf.org/html/rfc6455#page-5)から引用したリクエストとレスポンスはこちらです。

```HTTPリクエスト
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
```

```HTTPレスポンス
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
```

正直、websocketを使わないなら、使う場面は今のところないと思います。この記事では「こういうのがあるんやで！」というのが示せて、なんとなく101が意味することを察することができれば、良しとします。

websocketについてはこちらの記事や文献を参考にすると良いと思います(私がwebsocketを使うときが来たらちゃんと調べようと思います)。

- 参考リンク
  - [RFC6455](https://tools.ietf.org/html/rfc6455)
  - [WebSocketについて調べてみた。](https://qiita.com/south37/items/6f92d4268fe676347160)
  - [101 Switching Protocol](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/101)
  - [Protocol upgrade mechanism](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism)

### 2xx(Success)
2xxに分類されるStatus Codeはクライアントのリクエストがサーバによって上手く受け取られて、理解されたことを示します。
3xxとは違います。違いは3xxの概要で述べます。

- 200(OK)
リクエストが成功したことを示します。このStatus Codeはリクエストで使われていたHTTPメソッドによって意味することが違います。RFCにはGET/HEAD/POST/TRACE/PUT/DELETEの例がありますが、今回はGETのみ説明します。本当はPOSTもしたかったのだが、何を言っているのか分からなかったので、説明します。

  - GET<br>
リクエストされたリソースと一致する情報が返されたことをクライアントに伝えています。具体的に言うと、クライアントが```https://example.com/index.html```というリソースをリクエストした際に、サーバが返したリソースが```/index.html```である場合に、200が含まれたレスポンスが返されるということです。

- 204(No Content)
204はサーバがリクエストを上手く処理して、レスポンスにbodyを含まないということを示します。使われる場面としてドキュメントの自動保存機能などが挙げられます。
Qiitaもおそらく自動保存が完了した時点で204を含むレスポンスを返しています。Google Chromeの検証機能を使って確認してみたところ、自動保存が成功したタイミングで返ってくるレスポンスのStatus Codeは204であることが確認できます。ドキュメントの自動保存は文字が打ち込まれたタイミングで毎回ドキュメントを更新するための情報をサーバに送りつけています。その送りつけられた情報をもとに記事をサーバ側で更新し、その更新が正常に完了したということを表すために、204を返しているのでしょう。自動保存したタイミングで特に返すリソースはないはずなので、204を使っているのでしょう。

### 3xx(Redirection)
この3xxに分類されているStatus Codeはクライアントが行ったリクエストを完了するために、さらに多くのアクションを必要とすることを示しています。

- 302(Found)<br>
302 Foundはリクエストされたリソースが一時的に```Location```レスポンスヘッダーにセットされたURLに移されていることを示しています。
```Location```レスポンスヘッダーはバリューにURLを持ちます。このレスポンスヘッダーはリダイレクト先のURLを指します。
より詳細な情報が[302 Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302)に書いてあります。
 

### 4xx(Client Error)
- 400(Bad Request)
400 Bad Requestはサーバがクライアント側のエラーのせいでリクエストを処理できなかったことを示します。
クライアント側のエラーとして挙げられているのは以下です。
    - リクエストの文法が違う
    - 不正なリクエストメッセージが含まれている
    - 誤ったURLへのアクセスをしようとしている

- 参考リンク
  - [400 Bad Request](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400)

- 404(Not Found)
404 Not Foundはサーバがリクエストされたリソースを見つけることができなかったことを示します。
404はリクエストされたリソースが一時的に見つからないのか、永久的に見つからないのかをを示しているわけではありません。
もし、永久的にリソースが削除された場合は[410 Gone](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/410)を404の代わりに使います。

- 参考リンク
  - [404 Not Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404)

### 5xx(Server Error)
- 500(Internal Server Error)
500 Internal Server Erorrはサーバがリクエストを返させないようにする予期せぬ状況に出くわしたことを示します。
このStatus Codeは一般的には"Catch-all"なレスポンスです。サーバ管理者は同じエラーが起きないようにリクエストに関する詳細な情報とともに、500のようなStatus Codeを記録します。<br>
少しここは解釈を入れます。<br>
"Catch-all"とは「幅広く解釈できる」「包括的な」という意味があります。上述したように500は「サーバがリクエストを返させないようにする予期せぬ状況に出くわしたこと」と定義されており、かなり幅広い意味を持っていそうです。
サーバ管理者はこれだけ見ても、「どんなエラーが起きたのか？」「いつ起きたのか？」「起きたことによってどうなったのか？」などが全くわかりません。なので、サーバ管理者は同じエラーが起きないようにリクエストに関する詳細な情報とともに、500のようなStatus Codeを記録するのだろうと思います。

- 参考リンク
    - [500 Internal Server Error](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500)

## 終わりに
個人的には1xx系が読んでいて、全く知らなかったので、面白かったです。これからはWebSocketなどが使われる時代になる予感はするので、また実際の挙動などについて調べたいものです。
他の項目についてはRailsでちょいちょい見るStatus Codeについて書きました。Rails開発していてもStatus Codeぐらいはある程度知らないと、大変な目に合うかもしれないので、これを機にRFCかMDNを読んでみましょう。