🤙

覚えておきたいHTTPメソッド/ステータスコード

2023/03/01に公開

こんにちは。
株式会社オプティマインドでソフトウェアエンジニアをしております鳥居と申します。
私が所属するチームではWebアプリケーションおよびAPIを中心に、日々開発を行っています。
HTTPメソッドやHTTPヘッダ、ステータスコード等のWebにおける知識は、APIを設計・開発するにあたって必要不可欠であることに加え、ログのデータを見る際にも重要になってきます。
今回は、それらをしっかりと理解し正しい設計・開発ができるように、書籍から学んだことをアウトプットしていこうと思います。

HTTPメソッド

HTTPメソッドは、クライアントが行いたい処理をサーバに伝える役割がある。
リクエストにおいて、HTTPメソッドとリソースは対になっている。
一般的にはHTTPメソッドは行いたい処理の動詞になっており、リソースのURI(エンドポイントと呼ぶ)は、その処理の対象となる名詞になっている。

例: /listというURIに対して、GET(取得)する。

GET /list HTTP/1.1

HTTPメソッドは9つだけ

メソッド 意味 性質
GET 取得 べき等かつ安全
POST 作成 べき等でも安全でもない
PUT 更新、作成 べき等だが安全でない
PATCH 一部更新 べき等でも安全でもない
DELETE 削除 べき等だが安全でない
HEAD ヘッダの取得 べき等かつ安全
OPTIONS サポートされているメソッド一覧の取得 -
TRACE (説明省略※) -
CONNECT (説明省略※) -

HTTPメソッドの性質

性質 意味
べき等 ある操作を行っても結果が同じこと
安全 操作対象のリソースを変化させないこと

PUTやDELETEはべき等。同じリソースに何回発行しても、必ず同じ結果が得られる。
(PUTの例: リソースの内容が更新されている。→ 同じリクエストを再度送信しても、更新されているという結果が変わらない)
(DELETEの例: リソースが削除されている。 → 同じリクエストを再度送信しても、削除されているという結果が変わらない)

常にべき等であるPUTに対して、PATCHはべき等であるとは限らない。(そうなる可能性もある)
MDN web docsでは次のように説明されている。

例えば、自動インクリメントするカウンタフィールドがリソースの不可欠な部分である場合、 PUT は自然にそれを上書きしますが(すべてを上書きするので)、 PATCH は必ずしもそうとは限りません。

GETはべき等かつ安全。
リソースの状態に変化を与えることを「副作用」と呼ぶ。
GETには副作用がないため、同じリソースに何回発行しても、リソースの状態は変化しない。

POSTはべき等でも安全でもない。同じリソースに何回も発行してしまっては、結果で何が起きるか予測できない。
クライアントは、POSTを複数回送ることに慎重でなければならない。

※TRACEとCONNECTはほとんど使われていないため、それらを除いた6つのメソッドについて解説する。

GET(取得)

クライアントのGETリクエストに対して、サーバは指定されたURIに対応するデータをレスポンスとして返す。

リクエスト

GET /list HTTP/1.1
Host: example.jp

レスポンス

HTTP/1.1 200 OK
Content-Type: application/json

[
  { "uri": "http://example.jp/list/item1" },
  { "uri": "http://example.jp/list/item2" }
]

200: リクエストが成功したことを示すステータスコード。

POST(作成)

主に、3つの役割がある。
①子リソースの作成
②リソースへのデータの追加
③他のメソッドでは対応できない処理

①子リソースの作成

POSTの最も代表的な機能。
クライアントのPOSTリクエストに対して、サーバは新しい子リソースを生成し、そのURIに対応するデータをレスポンスとして返す。

リクエスト

POST /list HTTP/1.1
Host: example.jp
Content-Type: text/plain; charset=utf-8

hogehoge

レスポンス

HTTP/1.1 201 Created
Content-Type: text/plain; charset=utf-8
Location: http://example.jp/list/item3

hogehoge

201: 新しいリソースを生成したことを示すステータスコード。
Locationヘッダ: 新しいリソースのURI。

②リソースへのデータの追加

既存のリソースへデータを追加する。子リソースの作成ほど一般的な機能ではない。

リクエスト
(ログリソースへの追加例)

POST /log HTTP/1.1
Host: example.jp

2022-09-25T11:14:00Z, GET /log, 200

レスポンス

HTTP/1.1 200 OK

200: リクエストが成功したことを示すステータスコード。(再掲)
新しいリソースの生成(201)ではないため、ステータスコードは200を返す。

③他のメソッドでは対応できない処理

例を基にして解説する。
検索機能を用いて、以下のようにクエリパラメータを指定してリソースを取得したいとする。

http://example.jp/search?q={キーワード}

通常はGETリクエストを用いて取得を行いたいが、指定できるURIは実装上で長さ制限があり(※)、その長さを超えるURIでリクエストをかけることができない。
この場合は、POSTを用いてリクエストボディでクエリパラメータを指定する方法で実現する。

POST /search HTTP/1.1
Content-Type: application/x-www-form-urlencoded

q=very+long+keyword+..............

このように、他のメソッドでは実現できない機能はPOSTで代用する。

※URIの仕様上は長さ制限がないが、実装上では上限が存在する。

PUT(更新、作成)

リソースの更新

リクエスト
(POST①の例で作成したitem3のデータを更新する例)

PUT /list/item3 HTTP/1.1
Host: example.jp
Content-Type: text/plain; charset=utf-8

fugafuga

レスポンス

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

fugafuga

上記か、もしくはボディには何も入れずに、204を返す場合もある。

HTTP/1.1 204 No Content

204: レスポンスがボディを持たないことを示すステータスコード。

リソースの作成

リクエスト

PUT /newitem HTTP/1.1
Host: example.jp
Content-Type: text/plain; charset=utf-8

新しいリソース/newitemの内容

レスポンス

HTTP/1.1 201 Created
Content-Type: text/plain; charset=utf-8

新しいリソース/newitemの内容

201: 新しいリソースを生成したことを示すステータスコード。(再掲)
POSTの場合と異なり、PUTでは新しいリソースのURIを知っているため、Locationヘッダは入らない。

リソースの作成におけるPOSTとPUTの違い

メソッド 特徴
POST クライアントがリソースのURIを指定できない。(サーバ側で決定する)
PUT クライアントがリソースのURIを決定する。

上記の特徴から、設計上の指針として次のように使い分けるというものがあるが、これには注意点がある。

  • ランダムな文字列など、URIをサーバ側で自動的に決定するWebサービスの場合は POST を使う。
  • 記事のタイトルをURIに適用するなど、クライアントが設定したものでURIを決定するWebサービスの場合は PUT を使う。

後者の場合、リソースの上書きを避けるために、クライアントで事前にURIの存在をチェックしなければならないなどの配慮が必要になる。
また、URIに許可される文字や長さの制限など、クライアントがサーバの内部実装を知っている必要がある。
そのため、PUTの方がサーバとの結合が密になる。

特別な理由がない限りは、リソースの作成はPOSTで行う(URIはサーバ側で決定する)という設計が望ましい。

PATCH(一部更新)

PUTがリソース全体を置き換えるのに対し、PATCHではリソースの一部を更新する。

リクエスト

PATCH /users/12345 HTTP/1.1
Host: example.jp
Content-Type: application/json

{ "name": "piyo" }

レスポンス

HTTP/1.1 200 OK
Content-Type: application/json

{ "name": "piyo" }

上記か、もしくはボディには何も入れずに、204を返す場合もある。

HTTP/1.1 204 No Content

204: レスポンスがボディを持たないことを示すステータスコード。(再掲)

DELETE(削除)

リソースを削除する。

リクエスト

DELETE /list/item2 HTTP/1.1
Host: example.jp

レスポンス

HTTP/1.1 200 OK

上記もしくは、DELETEは一般的にレスポンスボディを持たないため、204を返す場合もある。

HTTP/1.1 204 No Content

204: レスポンスがボディを持たないことを示すステータスコード。(再掲)

HEAD(ヘッダの取得)

GETとよく似ているが、HEADの場合は、リソースのヘッダ(メタデータ※)のみを取得する。

リクエスト

HEAD list/item1 HTTP/1.1
Host: example.jp

レスポンス

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

ヘッダのレスポンスにはボディが含まれない。
利用目的として、ネットワークの帯域を節約しながらリソースのサイズを調べたり、リソースの更新日時を取得するなどがある。

※データを記述するデータ、データについてのデータのこと。

OPTIONS(サポートされているメソッド一覧の取得)

対象のリソースがサポートしているメソッドの一覧を返す。

リクエスト

OPTION /list HTTP/1.1
Host: example.jp

レスポンス

HTTP/1.1 200 OK
Allow: GET, HEAD, POST

Allowヘッダ: 許可されているメソッドの一覧を示す。尚、OPTIONS自体はこのヘッダに含めない。

ステータスコード

ステータスコードとは、リクエストがサーバによって処理された際のステータス、すなわち正しく処理が行われたのか、行われていないのであればどういった問題があったのかという概要を示すもの。
レスポンスに間違ったステータスコードを割り当ててしまうと、クライアントが適切な分岐を行えない結果を招き、システム全体の挙動に支障をきたす危険性がある。
特に汎用的なHTTPのクライアントライブラリは基本的にステータスコードを見て振る舞いをまず決める。
(例: 200番台なら成功、400番台ならエラーとみなして呼び出す処理を分岐する)
このように、ステータスコードはクライアントを左右する重要な役割を担っている。

ステータスラインの構成
ステータスラインは、レスポンスの1行目にある。
プロトコルのバージョン、ステータスコード、テキストフレーズで構成されている。

HTTP/1.1 200 OK

テキストフレーズ(上記の例では、OK)にはステータスコードに対応した説明句が入るが、仕様以外のフレーズを入れることも可能。

ステータスコードの5つの分類

ステータスコード 分類 意味
100 番台 処理中 処理が継続していることを示す。クライアントはそのままリクエストを継続する。
200 番台 成功 リクエストが成功したことを示す。
300 番台 リダイレクト 他のリソースへのリダイレクトを示す。クライアントはレスポンスのLocationヘッダを見て新しいリソースへ接続する。
400 番台 クライアントエラー クライアントのリクエストが原因で発生したエラーを示す。同じリクエストを再送信しても、エラーを解消しない限り正常な結果は得られない。
500 番台 サーバエラー サーバが原因で発生したエラーを示す。サーバの原因が解決すれば、同じリクエストを再送信して正常な結果が得られる可能性がある。

主なステータスコード

表内の太字は、中でも特に使われているステータスコードを示している。(全部で9個ある)
これらは数字とその意味が暗唱できるぐらいに、しっかりと押さえておく。

200番台: 成功

ステータスコード テキストフレーズ 説明
200 OK リクエストが成功した
201 Created 新しいリソースが生成された
202 Accepted リクエストが受け入れられた
204 No Content コンテンツなし

200 OK

リクエストが成功したことを示す。
レスポンスボディには、GETの場合リソースの表現が入り、PUTやPOSTの場合は処理結果が入る。

201 Created

リソースを新たに生成したことを示す。POSTとPUTのレスポンスとして返る。
リクエストがPOSTだった場合、Locationヘッダには新しいリソースの絶対URLが入る。

202 Accepted

リクエストが受け入れられたが、サーバ側で処理が完了していないことを示す。
POSTやPUTでリソースを作成・更新した際、その処理に非常に時間がかかりそうな場合に返す。
(例: ファイル形式の変換、Google Cloud Messagingなどのリモートノーティフィケーション)

204 No Content

リクエストが成功したものの、クライアントに返すコンテンツがないことを示す。
DELETEのレスポンスなどで利用する。

300番台: リダイレクト

ステータスコード テキストフレーズ 説明
300 Multiple Choices 複数のリソースが存在する
301 Moved Permanently リソースは恒久的に移動した
302 Found リソースは一時的に移動している
303 See Other 他を参照
304 Not Modified 前回から更新されていない
307 Temporary Redirect 302と同等
308 Permanent Redirect 301と同等

300番台のステータスコードのうち、リダイレクトに関するものは5つ。(301, 302, 303, 307, 308)
リダイレクトの場合、Locationヘッダにリダイレクト先の新しいURLが含まれる。

301 Moved Permanently

リクエストで指定したリソースが新しいURIに移動したことを示す。

302 Found

リクエストしたURIが存在しなかったため、別のURIにリクエストを再送信する必要があることを示す。

尚、現在は302の利用が推奨されていない。
リダイレクトのステータスコードの状況をまとめると、下記のようになる。

ステータスコード 意味(備考) メソッドの変更
301 (改めて308として定義し直された)
302 (改めて307として定義し直された)
303 POSTでデータ送信した後にGETで別ページを表示
307 別のURIにリクエストを再送信する。リソースは一時的な移動であることを表す 不可
308 ページ移転。リソースはこれから先ずっと移動したままであることを表す 不可

302本来の手法としては、リダイレクトのメソッドはリクエスト時のものと同じにする(例: POSTでリクエストしたならPOSTでリダイレクト先にアクセスする)ことになっていたが、ブラウザの多くが仕様に反して、POSTリクエストの後にGETでリダイレクト先を表示させるといった手法で使われてしまっていた。
そのため、のちに303と307が新しく定義され、上記の用途は303で、また302本来の用途は307として利用することを推奨されている。

303 See Other

リクエストに対する処理結果が別のURIで取得できることを示す。
リロード時にデータが再送されることを防ぐために、POSTでリソースを操作した結果をGETで取得するときに使う。

307 Temporary Redirect

リクエストしたURIが存在しなかったため、別のURIにリクエストを再送信する必要があることを示す。
302の代わりとして再定義されたものだが、今も302を使ってリダイレクトを行うケースが多く見られる。
302と異なり、メソッドの変更を許可していない。(例: GETでリクエストしたならGETでリダイレクト先にアクセスする)

308 Permanent Redirect

ページが移転したため、別のURIにリクエストを再送信する必要があることを示す。
301の代わりとして再定義されたもの。
301と異なり、メソッドの変更を許可していない。(例: GETでリクエストしたならGETでリダイレクト先にアクセスする)

300 Multiple Choices

リクエストしたリソースが複数の選択肢を持つ時に、その一覧のURIが返る。
(例: /fooにリクエストしたら、300で/foo.ja, /foo.en, foo.frが返る)

304 Not Modified

条件付きGETのリクエストに対して、リソースが更新されていないことを示す。
レスポンスボディは空になる。

400番台: クライアントエラー

ステータスコード テキストフレーズ 説明
400 Bad Request リクエストが正しくない
401 Unauthorized 認証が必要
403 Forbidden アクセスが禁止されている
404 Not Found 指定したリソースが見つからない
405 Method Not Allowed 指定されたメソッドは使うことができない
406 Not Acceptable Accept 関連のヘッダに受理できない内容が含まれている
408 Request Timeout リクエストが時間以内に成功しなかった
409 Conflict リソースが競合した
410 Gone 指定したリソースは消滅した
413 Request Entity Too Large リクエストボディが大きすぎる
414 Request-URI Too Long リクエストURIが長すぎる
415 Unsupported Media Type サポートしていないメディアタイプが指定された
429 Too Many Requests リクエスト回数が多すぎる

400 Bad Request

リクエストの構文やパラメータが間違っていることを示す。
また、他に適切なクライアントエラーを示すステータスコードがない場合にも用いる。

401 Unauthorized

認証(Authentication)のエラーを表す。
リクエストで適切な認証情報を与えていないことを示す。

403 Forbidden

認可(Authorization)のエラーを表す。
特定のIPアドレスのみからアクセスできる場合などに用いる。
403を返すとリソースが存在すること自体がクライアントに明らかになる。
存在を隠したい時は、404を使うこともできる。

「認証」と「認可」の違い

種類 意味
認証 アクセスしてきたのが誰であるのかを識別すること
認可 特定のユーザーに対してある操作の権限を許可すること

つまり、噛み砕くとこうなる。
401: 「あなたが誰だかわからないよ」
403: 「あなたが誰だかはわかったけどこの操作はあなたには許可されていないよ」

404 Not Found

指定したリソースが見つからないことを示す。

405 Method Not Allowed

リクエストしたHTTPメソッドが許可されていないことを示す。

406 Not Acceptable

リクエストのAccept-*ヘッダで指定した表現が返せないことを示す。
レスポンスボディは、300同様にサーバが用意できる選択肢の一覧が入る。
(例: Accept-Language: jaでリクエストしたが、サーバが用意しているのは.en, .frのみだった)

408 Request Timeout

リクエストをサーバに送るのが時間内に終わらないため、接続を切ったことを示す。

409 Conflict

他のリソースと競合する状態であることを示す。
リソースの名前をすでに存在するものに変更しようとした場合や、空ではないディレクトリを削除しようとした場合など。
(例: 「そのユーザ名はすでに使用されています」)

410 Gone

リソースが以前は存在したが、現在は存在しないことを示す。
アクセスしようとしたデータがすでに削除済みであることを表す。
(このステータスコードを返すには、「データを削除した」という情報保持が必要になる)

413 Request Entity Too Large

サーバが処理できないほどリクエストボディが巨大であることを示す。
サーバはクライアントからの接続を切断する。
(例: ファイルアップロードAPIに対して、許容されるサイズ以上のデータが送られてきた)

414 Request-URI Too Long

サーバが処理できないほどリクエストのURIが長すぎることを示す。
(例: GETのURIに含まれるクエリパラメータに長すぎるデータが指定された)

415 Unsupported Media Type

指定したメディアタイプをサーバがサポートしていないことを示す。
(例: 画像アップロードAPIに対して、サーバがサポートする形式はJPEGとPNGだけだが、リクエストでGIFの画像を指定された)

406と415の整理

ステータスコード 説明
406 クライアントが受け取りたい形式にサーバが対応していない。
Accept-*で指定したデータ形式にサーバが対応していない。
415 POSTやPUT、PATCHリクエストで送ってきたリクエストボディのデータ形式をサーバが対応していない。
Content-Typeで指定したデータ形式にサーバが対応していない。

429 Too Many Requests

アクセス回数が許容範囲の上限を超えたことを示す。
例えば、APIが1時間に100回しかアクセスできないように制限※がかかっていた場合に、101回以上アクセスをしようとするとこのステータスコードが返る。
(Retry-Afterヘッダで次にリクエストができる再開時期がおおよそ何秒後であるかを通知できる)

※この制限のことを「レートリミット」と呼ぶ。

500番台: サーバエラー

ステータスコード テキストフレーズ 説明
500 Internal Server Error サーバ側でエラーが発生した
503 ServiceUnavailable サーバが一時的に停止している

500 Internal Server Error

サーバ側に何らかの異常が生じていて、正しいレスポンスが返せないことを示す。
また、他に適切なサーバエラーを示すステータスコードがない場合にも用いる。

503 ServiceUnavailable

サーバがメンテナンスなどで一時的にアクセスできないことを示す。
(Retry-Afterヘッダでサービス再開時期がおおよそ何秒後であるかを通知できる)

メンテナンスは意図的なものであるが、意図的ではないケースでは、サーバが過負荷に陥ってレスポンスが返せなくなり、ロードバランサなどWebサーバの前段にいるサーバが返すケースが考えられる。

参考文献

この記事は以下の情報を参考にして執筆しました。

https://gihyo.jp/book/2010/978-4-7741-4204-3
https://www.oreilly.co.jp/books/9784873116860/

おわりに

最後までお読みいただき、ありがとうございました!
オプティマインドでは「多様性が進んだ世の中でも、全ての人に物が届く世界を持続可能にする」という物流業界の壮大な社会課題を解決すべく、 一緒に働く仲間を大募集中です。 少しでも興味が湧いた方は是非お気軽にカジュアル面談をお申し込みください!

https://recruit.optimind.tech/

Discussion