Webを支える技術③  ~HTTP~

# はじめに

前回「Webを支える技術」の概要とRESTについてまとめた。

今回はWebを支える技術の下記3つのうちURIについてまとめる。

1. URI
2. HTTP
3. HTML

# HTTPの基礎

## HTTPとは

Web上でやりとりするリソースの表現を、クライアントとサーバの間でやりとりするためのプロトコル。

クライアントはHTTPに従ってサーバにリクエストを送り、レスポンスを得る。

HTTPは、HTMLやXMLなどのハイパーテキストをはじめ、静止画、音声、動画、JavaScriptプログラム、PDFや各種オフィスドキュメントファイルなど、コンピュータで扱えるデータであれば何でも転送できる。

またHTTPはRESTの重要な特徴である統一インタフェース、ステートレスサーバ、キャッシュなどを実現する、Webの基盤となるプロトコルといえる。

## TCP/IP

HTTPはTCP/IPをベースにしたプロトコルなので、まずはTCP/IPについて知っておく必要がある。

まず、インターネットのプロトコルは階層型になっている。

ちなみに、ネットワークシステムを7つの階層に分けて表現したOSI参照モデルという概念も存在するが、インターネットの商用化に至る過程ではTCP/IPが事実上の標準プロトコル群として広く利用されるようになった。

TCP/IPの階層は下記の通り。

| 階層名 | 役割 | 具体例 |
| --- | --- | --- |
| アプリケーション層 | アプリケーションごとのやりとりを規定 | HTTP, NTP, SSH, SMTP, DNS |
| トランスポート層 | データの分割や品質保証を規定 | UDP, TCP |
| インターネット層 | ネットワーク間の通信を規定 | IP |
| ネットワークインターフェース層 | ハードウェアに関する規定 | イーサネット |

### ネットワークインターフェース層

一番下の層であり、物理的なケーブルやネットワークアダプタに相当する。

### インターネット層

ネットワークでデータを実際にやり取りする部分。TCP/ IPではIPが相当する。

IPではデータの基本的な通信単位をパケットと呼ぶ。

IPでは自分のネットワークインターフェースでデータを送り出すことだけを保証している。

送り出したデータが多数のルータを経由して、最終的な送り先まで届くかどうかは保証しない。

### トランスポート層

IPが保証しなかったデータの転送を保証する部分で、TCP/ IPではTCPが相当する。

接続先の相手に対してコネクションを張って、データの抜け漏れをチェックすることでデータの到達を保証する。

転送するデータがどのアプリケーションに渡るのかを決定するのはポート番号。

### アプリケーション層

具体的なインターネットアプリケーションを実現する層で、HTTPやDNS, メールなどが相当する。

TCPでプログラムを作る時はソケットと呼ばれるライブラリを使うのが一般的。

ソケットはネットワークでのデータのやり取りを抽象化したAPIで、接続や送信、受信などの基本的な機能を備えている。

HTTPサーバやブラウザはソケットを用いて実装する。

ほとんどのプログラミング言語にはHTTPを実装したライブラリが標準でついているため、ソケットを使ってHTTPを独自に実装することはほとんどない。

確かに普段PHPでHTTPリクエストを実装する際はGuzzleというクライアントライブラリを使うが、HTTP通信を実現している仕組みについては深堀りして勉強してみる必要があると思った。

## **HTTPメソッド**

HTTPメソッドには、クライアントが行いたい処理をサーバに伝えるという役割があり、以下の8つのメソッドがある。

1. GET：リソースの取得
2. POST：子リソースの作成、リソースへのデータの追加、その他の処理
3. PUT：リソースの更新、リソースの作成
4. DELETE：リソースの削除
5. HEAD：リソースのヘッダの取得
6. OPTIONS：リソースがエクスポートしているメソッドの取得
7. TRACE：自分宛てにリクエストメッセージを返す(ループバック)試験
8. CONNECT：プロキシ動作のトンネル接続への変更

この中でTRACEとCONNECTはほとんど使われないということで、本書ではそれ以外の6つについて説明されている。

### **HTTPメソッドとCRUD**

HTTPメソッドのうちGET、POST、PUT、DELETEは4つで「CRUD（クラッド）」という性質を満たす代表的なメソッドである。Create、Read、Update、Deleteの頭文字でCRUD。以下CRUDとHTTPメソッドの対応

- Create： POST/PUT
- Read： GET
- Update： PUT
- Delete： DELETE

### POST

あるリソースに対する子リソースを作成するのが代表的な機能だが、既存リソースへのデータ追加も行う。

リソースの作成ではレスポンスは201 Createdだがデータの追加では200 OKを用いる。

また、検索キーワードが長くなる場合にGETの代わりに使用したり、PUTやDELETEの代用でPOSTを使用することもある。

### PUT

リソースの更新と、リソースの作成を行う。

リソースの更新をしたPUTへのレスポンスは、200 OKとしてボディにレスポンスを入れても良いし、ボディには何も入れずに204 No Contentとしても良い。

PUTで指定したURIのリソースがまだ存在しない場合は、サーバはリソースを新しく作成する。

この時、POSTの場合は新しく作成したリソースのURIがLocationヘッダで返ってくるが、PUTの場合はクライアントは既にリソースのURIを知っているのでLocationヘッダで返ってこない。

### POSTとPUTの使い分け

POSTでリソースを作成する場合は、クライアントはリソースのURIを指定することはできず、URIの決定権はサーバ側にある。

逆にPUTでリソースを作成する場合は、リソースのURIはクライアントが決定する。

PUTの場合はサーバの内部実装（URIに使用可能な文字や長さなど）を熟知した上でクライアントで指定できるURIの制限をかけなければならず、サーバとの結合が密になる。

よって通常はPOSTを使い、サーバ側でURIを決定する設計が望ましい。

## べき等性と安全性

- べき等性：ある操作を何度行っても結果が同じこと。
- 安全性：操作対象のリソースの状態を変化させないこと。

HTTPメソッドをべき等性と安全性という性質によって分類すると、以下の通りになる。

| メソッド名 | べき等性 | 安全性 |
| --- | --- | --- |
| GET, HEAD | ○ | ○ |
| PUT, DELETE | ○ | × |
| POST | × | × |

これらは通信エラーが発生した時にリクエストをどう回復させるかに関わる。

POSTはべき等でも安全でもないため、通信エラーの後にもう一度POSTすると二重にリソースが作成される可能性があることに留意する必要がある。

ブラウザによって、ブラウザの戻るボタンを押した時に「もう一度送信しますか？」とダイアログが出るのは、POSTを再送しようとしている場合。

## ステータスコード

ステータスコードは3桁の数字であり、先頭の数字によって以下の5つに分類される。

**①1xx：処理中**

処理が継続していることを示す。クライアントはそのまま処理を継続するか、サーバの指示に従ってプロコトルをアップデートして再送信する。

**②2xx：成功**

リクエストが成功したことを示す。

**③3xx：リダイレクト**

ほかのリソースへのリダイレクトを示す。クライアントはこのステータスコードを受け取ったときにレスポンスメッセージのLocationヘッダを見て新しいリソースへ接続する。

**④4xx：クライアントエラー**

クライアントエラーを示す。原因はクライアントにリクエストにあり、エラーを解消しない限り正常な結果が得られないので、同じリクエストをそのまま再送信することはできない。

**⑤5xx：サーバエラー**

サーバーエラーを示す。原因はサーバ側にある。サーバ側の原因が解決すれば、同一のリクエストを再送信して正常な結果が得られる可能性がある。

よく使われるステータスコードとして、本書で挙げられていたのが以下の9つ。

- 200 OK
- 201 Created
- 301 Moved Permanently
- 303 See Other
- 400 Bad Request
- 401 Unauthorized
- 404 Not Found
- 500 Internal Server Error
- 503 Service Unavailable

301は「URIを変更する場合にはリダイレクトするようにURIを変更する場合にはリダイレクトするように」で説明されていた通り、URIを変更する際に設定しておくレスポンス。

本書では上記9つが紹介されていたが、個人的にはこの他によく見る気がするものもある。

Laravelで `return redirect()->route('test.index');`のようにリダイレクトの実装をすると、デフォルトでは「302 Found」になる。

「403 Forbidden」の権限エラーについても実装段階で配慮することが多い。（実装段階で制御しておくため、実際のアプリで発生することはあまり無いのかも、、？）

あとはタイムアウトの「504 Gateway Timeout」だとか、Laravel特有の話だがバリデーションエラーは「422」がデフォルトで返されるようになっている。

## さいごに

知っていることも多かったが、改めて体系的に勉強できてよかったところも、今後また勉強したいことも見つかった。

POSTとPUTの違いや使い分けの観点は、改めて整理できてよかった。

べき等性・安全性については、概要をつかむことはできたが、Web APIを設計する上では重要なポイントだと思うのでもう少し詳しく勉強したいのと、ソケットとHTTP通信を実現する仕組みについても深掘りしたい。