読者です 読者をやめる 読者になる 読者になる

Webを支える技術を研修で読んでる まとめ3

この記事について

技術研修で読み進めているWebを支える技術について、各章のまとめを順次上げていく。 前  pokotyamu.hatenablog.com

次 

HTTPメソッドの概要

HTTPメソッドには9つの種類がある。

メソッド 意味
GET リソースの取得
POST 子リソースの作成、リソースへのデータの追加、その他処理
PUT リソースの更新、リソースの作成
PATCH リソースの一部更新
DELETE リソースの削除
HEAD リソースのヘッド(メタデータ)の取得
OPTION リソースがサポートしているメソッドの取得
TRACE 自分宛てにリクエスト・メッセージを返す(ループバック)試験
CONNECT プロキシ動作のトンネル接続への変更

以降、各メソッドについて見ていく。 また、ステータスコードについては、次の第8章で述べる。 今回説明中で使用するステータスコードは、あくまで実装の一例である。そのため、実装のやり方によっては変化することがある。

各ヘッダの確認方法はGoogle Chromeの場合 以下の参考リンクのレスポンスヘッダのコピーを参照 参考:coliss.com - Chrome デベロッパーツールの使い方: プロのように華麗に使いこなすための20のテクニック

GETメソッド

GETでは、指定したURIの情報を取得する。 Webページの取得、画像の取得、映像の取得、フィードの取得など、実際にブラウザを利用している時に一番使われるメソッドがGETメソッドである。

GET / HTTP/1.1
Host: www.hottomotto.com
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Date: Tue, 26 Apr 2016 03:27:37 GMT
Server: Apache
Vary: Accept-Encoding
X-IIJ-Cache: MISS
Transfer-Encoding: chunked

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- 途中略 -->
</body>
</html>

レスポンス例のレスポンスボディー内に、指定したリクエストのhtmlの情報が返されている。 これを読み込んでWebブラウザ上で表示している。

POSTメソッド

POSTメソッドでは3つの役割が存在する。

子リソースの作成

ブログページを親とした時に、ブログ記事が子リソースに当たる。 つまり、ブログ記事の投稿がこの子リソースの作成に当たる。

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

こんにちは!
HTTP/1.1 201 Created
Content-Type: text/plain; charset=utf-8
Location http://example.jp/list/item5

こんにちは!

201 Createdというステータスコードが返ってきたが、これは正常にリソースの作成が出来たことを示す。 Locationヘッダにその新しいリソースのURIが入っている。

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

ログリソースの追加などがこれに当たる。

POST /log HTTP/1.1
Host: example.jp

2016-04-25T10:13:00Z, GET /log, 200
HTTP/1.1 200 OK

ここではPOSTのレスポンスとして、200が返ってきたが、これは、リソースの作成ではなく、データの追加を示す。 POSTがデータ作成を意味するか、またはデータ追加を意味するかは実装に依存するため、WebAPIの仕様書などを調べる必要がある。

他のメソッドでは対応出来ない処理

URIの長さにはブラウザの実装上2000文字以内などの制約が入る場面がある。 そのような長いキーワードの場合、URIのクエリにキーワードを入れてGETする方法は利用出来ない。 この時に POSTを利用することで、ボディの中にキーワードを格納することが出来る。

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

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

PUTメソッド

PUTは2つの役割が存在する。

リソースの更新

先ほどのPOSTの記事作成で作ったリソースの内容を更新する。

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

こんばんは!
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

こんばんは!

このように、PUTメソッドは、元のリソースを更新するときに使う

リソースの作成

http://example.jp/newitemが存在してないものとする。

POST /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の内容

PUTは存在しないURIへのリクエストのため、サーバはリソースを新しく作成すると解釈し、201 Createdを返す。 /newitemが存在していた場合は、更新として処理される。

PATCHメソッド

2010年のRFC7589で追加された一番新しいメソッド。 リソースの一部更新で使用される。 例えば、ブログ記事のタイトルの更新などに使用される。

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

##一部更新内容##
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

##一部更新が反映##

このように、基本的には、PUTの子リソースの更新となんら変わらない。 それぞれの違いについては後述する。

Github APIでも採用されているほか、Ruby on Rails v4.0から正式に採用された。

DELETEメソッド

名前の通りリソースの削除を行うメソッド

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

一般にDELETEのレスポンスはボディーを持たない。 そのため、ステータスコードにボディーがないという意味の204 No Contentが使われる場合がある。

POSTでPUT/DELETEを代用する

今現在、一番よく利用されているのが、GETとPOSTメソッドである。 HTMLのフォームで指定出来るのもこの2つだったが、技術の発展とともに、AjaxXMLHttpRequestというモジュールを利用することで、任意のメソッドを発行できるようになった。 しかし、XMLHttpRequestをサポートしない携帯電話向けブラウザでは2つのメソッドしか利用出来ない。 また、プロキシサーバではPUTによって勝手にサーバーに関する情報をクライアントに追加させたり置き換えさせたりするため、セキュリティの問題で2つのメソッド以外のアクセスを制限する場合がある。

このような状況で、サーバにPUTやDELETEを伝えるためには、

  • _methodパラメータ
    • フォームの隠しパラメータに_methodというパラメータを入れる
    • その中に本来送りたかったメソッドの名前を入れる
    • Ruby on Railsが採用している
  • X-HTTP-Method-Overrde
    • XMLなどの場合に使用
    • X-HTTP-Method-Overrdeヘッダにメソッド名を指定することで、実現する
    • GoogleGoogle Data Protocolが採用している

HEADメソッド

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

HEAD /list/item1 HTTP/1.1
Host: example.jp
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

先述した通り、ヘッダのみ返すため、HEADへのレスポンスにはボディーを含まない。 利用用途としては、ネットワークの帯域を節約しつつ、リソースの大きさや、更新日時を調べるために使う。

OPTIONSメソッド

OPTIONSは、そのリソースがサポートしているメソッドの一覧を返す。

OPTIONS /list HTTP/1.1
Host: example.jp
HTTP/1.1 200 OK
Allow: GET, HEAD, POST
OPTIONS /list/item1 HTTP/1.1
Host: example.jp
HTTP/1.1 200 OK
Allow: GET, HEAD, PUT,DELETE

OPTIONS自体は、Allowヘッダには含めない。 また、OPTIONSメソッドは開発者が独自で実装しなければならない。

主要ではないHTTPメソッド

今まで説明した、7つのメソッドが主にHTTPメソッドとしては使われやすい。 ここからは、少し使用頻度の低い2つのメソッドについて説明していく。

TRACEメソッド

TRACEは、HTTPリクエストを「オウム返しに」HTTPレスポンスとして返す。 ただし、注意すべき点として、リクエストをそのまま返すため、レスポンスの中にCookieヘッダAuthorizationヘッダも含まれてしまう。 そのため、Cross-Site Tracing(XST)攻撃に利用された。 XST攻撃とは、XSS^1とTRACEメソッドを組み合わせた攻撃手法である。 以下、徳丸浩の日記 - 実はそんなに怖くないTRACEメソッドから引用

XSS単独では、XSSによりJavaScript等が動いているブラウザ上のレスポンス(ヘッダ及びボディ)は取得出来ますが、リクエストヘッダを取得することはできません。このため通常は、HttpOnly属性の指定されたCookieや、Authorizationヘッダ(Basic認証のIDとパスワード)を取得することはできません。 しかし、TRACEメソッドを実行すると、先に見たようにリクエストヘッダがそのままレスポンスとして返るので、XSS単独ではとることのできないHttpOnly属性の指定されたCookieや、Authorizationヘッダを盗み出すことができます。これがXST攻撃です。とくに、BASIC認証のIDとパスワードを盗むことができると、長期にわたって不正にログインすることができてしまうため、XSSの影響が大きくなります。

CONNECTメソッド

RFC 2817の定義によると

A CONNECT method requests that a proxy establish a tunnel connection on its behalf. The Request-URI portion of the Request-Line is always an 'authority' as defined by URI Generic Syntax [2], which is to say the host name and port number destination of the requested connection separated by a colon:

```レスポンス例 CONNECT server.example.com:80 HTTP/1.1 Host: server.example.com:80

日本語に軽く訳すと、 「CONNECTは、proxyとのトンネル接続を作るために使われる。リクエストURIの中にhostme名、ポート番号、リクエスト元の情報がコロン区切りで記述される。これらは、URIの一般的なシンタックスである。」

べき等性と安全性

べき等とは「ある操作を何回行っても結果は同じという考え方」である。 数学の絶対値、0の乗算(3 * 0 = 0)などがあげられる。

また、安全性とは「操作対象のリソースの状態を変化させないこと」を意味している。

これらを主要メソッドであるGET、POST、PUT、PATCH、DELETE、HEADに当てはめると次のような図に分類出来る

安全性あり 安全性なし
べき等 GET、HEAD PUT、DELETE
べき等でない POST,PATCH

GETとHEADは、値を取ってくるだけなのでべき等かつ安全なのは自明である。 PUTとDELETEは、値を更新や作成、削除する点から変化を与えるため安全性はないが、何度やっても値は同じなのでべき等性はある。 POSTは、リクエストの結果次第で何が起こるか分からないためべき等性はなし。更に、リソースの状態に変化も与えるため安全性もなし。 POSTの例としては、通販サイトでのブラウザの戻るボタンを押してしまった時に、2重注文のような問題が発生する可能性を示している。 PATCHは、更新の時に、べき等でなく、安全性もない更新であると定義されている。

POSTとPUTとPATCHの使い分け

POSTとPUT

どちらも新しいリソースの作成を行えるが、それぞれの使い分ける指針として、 リソースのURI決定権が挙げられる。

POSTでリソースを作成する場合、URIの決定権は サーバ側にある。 なので、レスポンスヘッダー内にLocationが含まれる。 この動作の例としては、TwitterのようにUTIをサーバーが自動的に作成する場合が挙げられる。

PUTでリソースを作成する場合、 クライアントが決めたURIがそのままサーバ側で使用される。 なので、レスポンスヘッダー内でLocationが含まれていない。 この動作の例としては、Wikiのようにクライアントが決めたタイトルがそのままURIになるものが挙げられる。

PUTとPATCH

Ruby on Rails(以下Rails)の導入された経緯から、この2つのメソッドの違いを考える。 元々Railsでは、レコードの更新に対して、PUTメソッドが使われていた。 Railsで使用するレコードの中にはupdate_atという更新時間の項目が常に含まれている。これは、ユーザが指定していない時でも作成される。 この時、レコード内の別の項目だけを更新した時にupdate_atも一緒に更新時間が変わってしまう。つまり、同じ更新を行う時に毎回同じ結果が返るという べき等性が失われている。 そこで、最初からべき等性も安全性もない、PATCHメソッドを用いることで、この誤用を解消した。

このように、PUTとPATCHは基本的に処理内容としては、同じだが、べき等性が必要か否かで選ぶと良い。 参考:Edge Rails - PATCH is the new primary HTTP method for updates

メソッドの誤用

先ほど、べき等性と安全性の対応表を出したが、全てがあの表に当てはまるとは限らない。 そのパターンについて述べる。

なお、これらのパターンは開発者の問題であることが多く、前述した図が基本と考えて良い。 そのため、べき等性や安全性を考慮して、適切なメソッドを適切なタイミングで使用することを心がける。

GETが安全でなくなる場合

GET: /resources/1/delete HTTP/1.1
Host: example.jp

このようにGETで要求しているにもかかわらず、example.jp/resources/1 を削除しようとする時、安全性がなくなる。 これを防ぐためには、GETの発行前後でリソースに変化が入っていないか?を考えると良い。 基本的にGETでは参照しか出来ないはずなので、deleteなどの動詞がURIに入ってる段階で矛盾している。

PUTがべき等でなくなる場合

価格の更新に対して、現在の価格の50%増加させるといったように、今の差分から処理を行う時 毎回結果が変わってくるため、べき等性がなくなる。 このようなときには、PATCHを使うか、「+50%」といった相対的な表現を避けるべきである。

DELETEがべき等でなくなる場合

ソフトウェアの最新バージョンがhttp://example.jp/latestというエイリアスリソースで管理されている時、このURIに対してDELETEを行うとどうなるか? もし、エイリアスリソースそのものを削除するという処理の場合、http://example.jp/latestが削除されるだけなので、べき等性は保たれる。 しかし、エイリアス先のリソース(最新バージョンのリソース)を指していた場合、ver2.0が削除された次の削除はver1.9になるため、べき等性がなくなってしまう。

このようにエイリアスリソースを削除するように設計するのもいいが、このような特殊なリソースについては、更新や削除などの操作が出来ないような設計にするのが求められる。

CRUDな設計

これまで、9つのHTTPメソッドの種類をまとめた。 これらのメソッドのうち、GET、POST、PUT、DELETEは4つでCRUDという性質を満たす。 CRUDとは、

  • Create:作成、生成
  • Read:読み取り
  • Update:更新
  • Delete:削除

の4つの頭文字を取ったものである。

それぞれの対応関係は、以下の図のようになっている。

CRUD 意味 メソッド
Create 作成 POST、PUT
Read 読み込み GET
Update 更新 PUT
Delete 削除 Delete

CRUDな設計の代表例は、railsのscaffoldした雛形Webアプリケーションが挙げられる。 参考:TECHSCORE - 4.scaffoldを利用した開発(1)