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つだったが、技術の発展とともに、AjaxのXMLHttpRequestというモジュールを利用することで、任意のメソッドを発行できるようになった。 しかし、XMLHttpRequestをサポートしない携帯電話向けブラウザでは2つのメソッドしか利用出来ない。 また、プロキシサーバではPUTによって勝手にサーバーに関する情報をクライアントに追加させたり置き換えさせたりするため、セキュリティの問題で2つのメソッド以外のアクセスを制限する場合がある。
このような状況で、サーバにPUTやDELETEを伝えるためには、
- _methodパラメータ
- フォームの隠しパラメータに_methodというパラメータを入れる
- その中に本来送りたかったメソッドの名前を入れる
- Ruby on Railsが採用している
- X-HTTP-Method-Overrde
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)