覚えておきたいHTTPメソッド/ステータスコード
こんにちは。
株式会社オプティマインドでソフトウェアエンジニアをしております鳥居と申します。
私が所属するチームでは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サーバの前段にいるサーバが返すケースが考えられる。
参考文献
この記事は以下の情報を参考にして執筆しました。
おわりに
最後までお読みいただき、ありがとうございました!
オプティマインドでは「多様性が進んだ世の中でも、全ての人に物が届く世界を持続可能にする」という物流業界の壮大な社会課題を解決すべく、 一緒に働く仲間を大募集中です。 少しでも興味が湧いた方は是非お気軽にカジュアル面談をお申し込みください!
Discussion