# Webを支える技術 第3部 HTTP ## 第6章 HTTPの基本 ### 6.1 HTTPの重要性 HTTPはRFC2616で規定(HTTP1.1)されたプロトコルである。 ハイパーテキストだけでなく、静止画や動画、JavaScriptプログラム等を転送できる。 ### 6.2 TCP/IP TCP/IPの解説はWeb技術入門を参照。[リンク](https://hackmd.io/MhFaz5FNQyGMBXtmb_iatw?view#33-TCPIP) 階層型プロトコルのうち、TCPはトランスポート層、IPはインターネット層に該当する。なお、HTTPはアプリケーション層である。 ### 6.3 HTTPのバージョン #### 6.3.1 HTTP0.9 HTTP0.9というバージョンが存在するわけではないが、1.0リリースの前にBerners Lee氏が使っていたとされるHTTPプロトコル。 ヘッダが無くボディ部分のみの簡潔な構造で、GETメソッドのみが利用できた。 #### 6.3.2 HTTP1.0 HTTPの初代バージョンとして登場したのがHTTP1.0である。IETFで初の標準化が行われた。 1993年に初のドラフトが公開され、1996年に最終バージョン(RFC1945)がリリースされた。 折しもIEとNetscapeのブラウザ戦争時代で、仕様策定前に独自仕様を実装したため、インターネットスタンダードにはならなかった。 機能面ではヘッダの追加やメソッドの追加が行われた。 #### 6.3.3 HTTP1.1 現在利用されている最新プロトコルである。 1997年にRFC2068, 99年にはRFC2616として標準化されている。 チャンク転送やAcceptヘッダの利用、複雑なキャッシュコントロール、持続的接続等の機能が加わった。 #### 6.3.4 HTTPのその後 HTTPの議論はその後も続けられたが、新バージョンのリリースには至っていない。HTTP1.1を有効活用することが現代的な開発スタイルとなっている。 2008年ごろから、HTTP1.1の仕様の完成度を上げる取り組み「HTTP Bits」が始まっている。 ### 6.4, 6.5 クライアント/サーバによるリクエストとレスポンス HTTPは、Webのアーキテクチャスタイルであるクライアント/サーバ間において、クライアントのリクエストを処理してレスポンスを返す。 #### 6.5.1 クライアントで行われること 1. リクエストメッセージの構築 2. リクエストメッセージの送信 3. レスポンスが返るまで待機 4. レスポンスメッセージの受信 5. レスポンスメッセージの解析 6. クライアントの目的を達成するために必要な処理(再リクエスト、HTMLのレンダリング等) #### 6.5.2 サーバで行われること 1. リクエストの待機 2. リクエストメッセージの受信 3. リクエストメッセージの解析 4. 適切なアプリケーションプログラムへの処理の依頼 5. アプリケーションプログラムから結果を取得 6. レスポンスメッセージの構築 7. レスポンスメッセージの送信 ### 6.6 HTTPメッセージ HTTPメッセージの詳細はWeb技術入門を参照。[リンク](https://hackmd.io/MhFaz5FNQyGMBXtmb_iatw?view#321-%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E6%83%85%E5%A0%B1) ### 6.7 HTTPのステートレス性 HTTPのステートレス性の詳細はWeb技術入門を参照。[リンク](https://hackmd.io/0IltfiD3QJS3O2wBKl_M6A#451-%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88%E3%83%AC%E3%82%B9%E6%80%A7%E3%81%AB%E5%AF%BE%E5%87%A6%E3%81%99%E3%82%8B) #### ステートフルの利点と欠点 * 利点 * 会話が簡潔になる。 * サーバがクライアントのリクエストを覚えている。 * 欠点 * 1台のサーバの記憶には限界がある。 * サーバ台数が増えるほど同期のためのオーバーヘッドが生じやすい。 #### ステートレスの利点と欠点 * 利点 * リクエストごとに必要なメッセージが全て含まれている。(自己記述的メッセージ) * サーバ側のシステムが単純となる。 * 欠点 * リクエストのデータ量の多さや、認証処理などのサーバに負荷がかかる処理により、パフォーマンスが低下する。 * 通信エラーに対する対処が難しく、2重処理となりやすい。 ## 第7章 HTTPメソッド ### 7.1, 7.2 8つのメソッドとCRUD HTTP1.1で用いるメソッドは8つのみである。 中でも、**GET, POST, PUT, DELETEは、データ操作の基本となるCRUDという性質を満たす。** (CRUDについてはWeb技術入門を参照。[リンク](https://hackmd.io/0IltfiD3QJS3O2wBKl_M6A?view#521-RDBMS%E3%81%AE%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C%E3%81%A8%E5%87%A6%E7%90%86)) ### 7.3 GET:リソースの取得 GETメソッドは、指定したURIの情報を取得するメソッドである。 CRUDのREADの役割を果たす。 正常通信時、メッセージ200 OK及びURIのデータが、レスポンスとして返される。 ### 7.4 POST:リソースの作成・追加 POSTメソッドは、指定したURIの情報を新規作成したり追加したりするメソッドである。 CRUDのCREATEの役割を果たす。 具体的には以下の3つの役割を持つ。 #### 7.4.1 子リソースの作成 あるリソースに対する子リソースの作成を行う。 親リソースのパスに追加して子リソースを作成し、その子リソース情報を追加する。 具体例としてはブログの投稿の操作等がある。 正常通信時、メッセージ201 Createdが返る。 (例)親リソース:http://example.jp/animation POSTで/aikatsuにアイカツ!を追加 子リソース:http://example.jp/animation/aikatsu でアイカツ!が表示される。 #### 7.4.2 リソースへのデータ追加 新規作成だけでなく、データ追加時もPOSTを利用する。 方法は子リソースの作成時と同様に、子リソースのパスと追加内容を入力する。 正常通信時、メッセージ200 OKが返る。 なお、データの追加位置や、作成・追加の区別等はサーバ側の実装に依存する。 #### 7.4.3 他のメソッドでは対応できない処理 処理が他のメソッドで実現できない場合はPOSTメソッドが担う。 有名なのは、URIにおけるリクエストパラメータの送信である。 GETメソッドでは、URIにリクエストパラメータが記載されるが、 URIに上限が存在する場合や、セキュリティ上パラメータを秘匿としたい場合はPOSTメソッドを用いる。 POSTメソッドではリクエストボディにリクエストパラメータが入るため、URIに表出する心配なくデータを取得できる。 ### 7.5 PUT:リソースの更新・作成 PUTメソッドは、リソースの更新や作成ができるメソッドである。 CRUDのUPDATE及びCREATEの役割を果たす。 #### 7.5.1 リソースの更新 PUTメソッドの代表的な利用方法はリソースの更新である。 既存のリソースの一部を修正する場合等に用いる。 正常通信時、200 OK又は204 No Contentが返る。 #### 7.5.2 リソースの作成 既存のリソースが存在しないURIへのリクエストの場合、 新規作成となりPOSTメソッドの子リソースの作成と同様の役割を果たす。 正常通信時、メッセージ201 Createdが返る。 但しレスポンスヘッダにはLocationを返す必要がない。(既に知ってるため) #### 7.5.3 POSTとPUTの使い分け POSTとPUTの新規作成は、設計上の指針として以下の事実がある。 * POSTは原則として**URIをクライアントは指定しない。URIはサーバ側で作成される。** * POSTの利用例 * ブログ * SNS(Twitter等) * PUTは原則として**URIをクライアントが指定する。** クライアントの指示に基づきURIが作成される。 * PUTの使用例 * Wikipedia(URIの名前も任意性が必要) ### 7.6 DELETE:リソースの削除 DELETEメソッドは、リソースを削除するメソッドである。 その名の通り、CRUDのDELETEの役割を果たす。 正常通信時、200 OK又は204 No Contentが返る。 ### 7.7 HEAD:リソースのヘッダ取得 HEADメソッドは、リソースのヘッダ部分のみを取得するメソッドである。 GETメソッドとの違いはボディが含まれないところであり、ネットワーク帯域の節約が可能となる。 ### 7.8 OPTIONS:リソースがサポートするメソッドの取得 OPTIONSメソッドは、リソースがサポートするメソッド一覧を取得するメソッドである。 このメソッドでリクエストを送信すると、レスポンスにAllowヘッダが記載される。 Allowヘッダには利用できるメソッド名(OPTIONS以外)が一覧で記載される。 なお、多くのWebアプリケーションフレームワークでは、OPTIONSの適用には独自の実装が必要である。 #### 7.9 HTMLフォームとPOSTによるPUT・DELETE テキストボックス、ラジオボタン、プルダウン等のHTMLフォームは、GETメソッド及びPOSTメソッドのみが利用できる。 現在ではAjaxのモジュールでPUTメソッド・DELETEメソッドを利用可能だが、そのモジュールをサポートしていない場合は利用できない。 また、セキュリティ上の観点でPUT・DELETE両メソッドに対し、プロキシサーバーがアクセス制限を行っている場合もある。 こうした状況で両メソッドの操作を伝える方法が2つある。 #### 7.9.1 _methodパラメータ HTMLフォームの隠しパラメータを利用してリクエストを伝達する方法である。 RubyOnRailsで採用されており、_method部分がそのまま採用メソッドとなる。 #### 7.9.2 X-HTTP-Method-Override POST内容がXML文等、URLの形式以外では先ほどのパラメータは利用できないが、 GoogleのGDataが利用するX-HTTP-Method-Overrideヘッダを利用すれば伝達できる。 ### 7.10 条件付きリクエスト リクエストの実行に条件を付けたい時は、If-から始まるヘッダをつけることで、条件付きリクエストを表現できる。 (例) If-Modified-Since:リソースがこの日時以降に更新されていれば取得する。 If-Unmodified-Since:リソースがこの日時以降に更新されていなければ取得する。 ### 7.11 べき等性と安全性 HTTPでは、プロトコルのステートレス性を保ちながら、通信エラー時のリクエストの回復するための工夫がなされている。 #### 7.11.1 べき等 **べき等**とは、「**ある操作を何度行っても同じ結果が返る**」ことを意味する数学用語である。(0の掛け算や絶対値の関数等が該当する。) ここではGET、PUT、DELETE、HEADメソッドが該当する。 GET及びHEADはリソースを取得するだけなので、何度行っても変化は無いためべき等となる。 一方PUTは、更新や作成という任意のURIに対する変更は何度行っても同じ結果のため、べき等となる。 DELETEも、任意のURIに対する削除処理には何度行っても同じ結果のため、べき等となる。 なお、GETやHEADはリソースに変化を及ぼさないため、通信がエラーとなっても安全である。 #### 7.11.2 POST **POSTはべき等でも安全でも無い唯一のメソッドである。** もし通信エラーが発生した場合等に送り直しを行った場合、二重送信となってしまう。 通販サイト等、セッション性のあるサイトでは、ブラウザの「戻る」ボタンを押すと「フォーム再送信の確認」の表示が出る。 これはPOSTメソッドの再送信の確認であるため、二重送信とならないようブラウザの戻るボタンを利用しないようにする必要がある。 ### 7.12 メソッドの悪用 本来の目的以外でメソッドを利用する場合、安全性やべき等性を損ねる場合がある。 #### 7.12.1 GETが安全でなくなる例 GETが安全性を損ねる場合:deleteやupdate,set等、リソース内容を更新する内容である場合 #### 7.12.2 POSTメソッドの誤用 べき等でも安全でもないPOSTメソッドで、これらの性質の全部や一部が保障されている他のメソッド内容で十分可能な内容を実現するのは誤用である。 XML-RPCや、第2章でRESTと覇権を争ったSOAPはこの代表例で、呼び出し、更新、削除まであらゆる操作をPOSTで実現するものである。 #### 7.12.3 PUTがべき等でなくなる例 PUTがべき等性を損ねる場合:計算処理(+50)等、相対的な差分を送信する場合、繰り返すことで値が変化してしまう。 #### 7.12.4 DELETEがべき等でなくなる例 DELETEがべき等性を損ねる場合:latest等、具体的なURIでなく時間や状況でリソースを指し示す場合、削除されるものが変化してしまう。 エイリアスリソースを使うのも一手ではあるが、できる限り時間や状況で指し示すリソースは更新・削除しないよう心掛ける。 ## 第8章 ステータスコード ### 8.1~8.3 ステータスコードの位置付けと意味 ステータスコードは、レスポンスのステータスラインに表示される、数字とコメントの羅列である。 このステータスコードにより、HTTPを用いた処理の結果が一目でわかる他、**レスポンス後のクライアント処理に対する重要な指標となる。** ステータスコードの分類については、Web技術入門を参照。[リンク](https://hackmd.io/MhFaz5FNQyGMBXtmb_iatw#322-%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E6%83%85%E5%A0%B1) ### 8.4 よく用いられるステータスコード #### 200番台:正常処理完了 * 200 OK:最も基本的なステータスコードである。大半のリクエストの正常処理完了を示す。 * 201 Created:リソースが正常に作成された場合に返される。POST及びPUTメソッドのレスポンスで返される。 #### 300番台:リソースの移動 * 301 Moved Parmanently:リソースが別URIに恒久的に移動している状況を示す。いわゆるリダイレクト処理で返されるレスポンスである。このレスポンスを受け取ると、クライアントはLocationヘッダに記載されているURIに自動的にリクエストを行う。 * 303 See Other:リクエストの処理結果が別URIに存在している状況を示す。クライアントは同様にLocationのURIにリクエストを行う。 #### 400番台:クライアントエラー * 400 Bad Request:リクエスト自体に誤りがある場合や、その他のクライアントエラー時に表示される。例:パスワード設定時の条件を満たさない場合 * 401 Unauthorized:アクセス権限に不正がある場合に表示される。適切な認証情報が与えられない場合に表示され、認証方式が返される。 * 404 Not Found:リソースが見つからない場合に表示される。リンク切れやURIの誤入力等が主な理由である。エラー情報が返される。 #### 500場合:サーバエラー * 500 Internal Server Error:サーバによるエラー全般に表示される。具体例として、プログラムにおける例外処理等がある。エラー情報が返される。 * 503 Service Unavailable:サーバによるサービスが停止されている場合に表示される。サーバの点検時にアクセスする場合等。復旧見込み時間が返される。 ### 8.5 ステータスコードとエラー処理 エラーメッセージにおけるステータスコードは、ボディ部分に何を加えるかは定義されていない。 そのため、製作者側で任意のメッセージを返すことができる。 通常はクライアントが理解しやすいようなメッセージを入力する。 また、Atom形式のようにプロトコルに従ったフォーマットでエラーを返したり、Acceptヘッダに応じて形式を変えてエラーを返すこともできる。 ### 8.6 ステータスコードの悪用 ステータスコードの悪用事例としては、エラーを正常処理として返すものがある。 これは、エラーメッセージをWebAPIやWebサービスの固有の形式で返す場合に発生する。 通常のブラウザでエラーメッセージを認識できない場合は、エラーであるにも関わらず200 OKが返る場合があり、誤った処理が行われてしまう可能性がある。 ステータスコードは仕様で固定されているので、正しく使えるような設計が重要である。 ## 第9章 HTTPヘッダ ### 9.1, 9.2 HTTPヘッダの重要性とその生い立ち HTTPヘッダは、メッセージボディに対する付加的な情報であるメタデータを記述する部分である。 HTTPヘッダはHTTP0.9では存在しておらず、1.0で**電子メールのメッセージ仕様のヘッダ形式を借りる形で追加された**経緯がある。したがって、HTTPヘッダを理解するには電子メールの仕様を知る必要がある。 その後、一度の通信でリクエストとレスポンスをやり取りするHTTPの特徴を活かした、HTTP特有のヘッダが追加されている。 ### 9.3 日時 値に日時を持つヘッダは以下の通り。 * Date:メッセージの生成日時を表す。 * If-(Un)Modified-Since:リクエストで、リソースの更新日時を条件に指定する。ModifiedはGET, UnmodifiedはPUT,DELETEで用いる。 * Expires:レスポンスで、キャッシュ可能な期限を返す。 * Last-Modified:レスポンスで、最終更新日時を返す。 * Retry-After:サーバ点検中などでリクエストが送れない場合、レスポンスで受付再開目安の日時を返す。 なお、HTTPで扱う時刻表記は世界基準のグリニッジ標準時(GMT)のみとなる。(日本の場合GMTは-9hのため、日本標準時に直す場合は+9hが必要。) ### 9.4 MIMEメディアタイプ 画像、音声、動画といったマルチメディアの種類や、文字エンコーディングの形式を指定する。 MIME(MultiPurpose Intarnet Mail Extentions)の仕様から拝借している。 #### Content-Type メディアタイプを指定する。タイプは全9つあり、/で区切ってサブタイプを指定する。 加えて、+xmlなど、XMLのメディアタイプの場合は接尾辞がつく。 コンテントタイプはIANAによって管理されている。 * 人が直接理解可能な文字データ(text) * プレーンテキスト(plain) ※text/plainのように表記する * 画像データ(image) * JPEG形式(jpeg) * PNG形式(png) * 音声データ(audio) * WAV形式(wav) * MP3形式(mp3) * 映像データ(video) * MP4形式(mp4) * その他のデータ(application) * PDF形式(pdf) * JSON形式(json) * 複合データ(multipart) * related * 電子メールメッセージ(message) * rfc822 * 複数次元で構成するモデルデータ(model) * vml * 例示用 * foo-bar #### charsetパラメータ 文字エンコーディングの形式を指定する。 textのデフォルト文字コードはISO 8859-1であるため、日本語を入力すると文字化けが発生しやすい。 日本語を含む場合は、charset=UTF-8と指定するのが無難である。 また、XML形式の場合は上述の接尾辞がつくコンテントタイプ指定を行い、charsetパラメータを指定するのが無難である。 ### 9.5 言語タグ リソース表現の自然言語(日本語、英語etc...)を指定する。 ヘッダはContent-Ranguageで、言語指定-地域コードの順で表す。 * 言語指定:ja, en 等 * 地域コード:JP, US, GB 等 ### 9.6 コンテントネゴシエーション サーバがクライアントと協調してメディアタイプの詳細を決定していく手法を、コンテントネゴシエーションという。 代表ヘッダとしてAcceptがあり、Accept-〇〇で項目別に指定できる。 #### Accept 処理できるタイプを伝える * Accept:Accept単独で用いる場合は、クライアントからリクエストされたメディアタイプに対応しているかどうかを返す。対応していない場合は 406 not Acceptableが返る。 * Accept-Charset:クライアントが使用可能な文字エンコーディングをリクエストヘッダで伝える。各エンコーディングの優先度を、少数の割合表記にて指定可能である。 * Accept-Ranguage:同様に、クライアントが使用可能な自然言語を伝える。優先度も指定可能。 ### 9.7 Content-Lengthとチャンク転送 #### 9.7.1 Content-Length メッセージがボディを持つ場合に、そのサイズを10進数のバイト数で表す。 (例)Content-Length : 5530 #### 9.7.2 チャンク転送 ボディを分割した上で転送する。Transfer-Encodingにchunkedを指定すると、最終的なサイズが分からなくても自動的にボディを転送する。チャンクは16バイト単位で文字で覚えるため、16進数である。また、チャンクはHTTP1.1で必須対応となっている。 Transfer-Encoding : chunked ### 9.8 認証方式 認証方式は、WWW-Authenticateヘッダにより、クライアントはサーバの認証方式を理解することができる。 #### 9.8.1 Basic認証 ユーザーネームとパスワードによる、一般的な認証方式。エンコーディングは簡単にデコードできるため、セキュリティ面においては不向きである。利用する場合は通信経路の暗号化(SSLやHTTPSなど)を行う必要がある。 #### 9.8.2 Digest認証 あるメッセージに対してクライアントはハッシュ関数を用いてダイジェストを作成して送信し、サーバはハッシュ値を求めて解錠する方式。 公開鍵暗号方式や、ディジタル署名と同じハッシュ関数の仕組みが利用されており、安全性が高い。但し、メッセージ自体は平文なので、通信経路の暗号化は必須である。また、ハッシュ値はnumber used onceのため、2回目以降のログインにハッシュ値は使いまわせず、操作が煩雑になる欠点がある。 ヘッダには、nonce(ハッシュ値)、qop(ダイジェストの作成方法指定)、opaque(クライアントには不透明な文字列)の3つを指定する。 * nonce:タイムスタンプ(リクエストの有効期限の短縮)や、サーバのみが知るパスワードなどで作成したハッシュ値。 * qop   * auth:メソッド、URIでダイジェスト生成   * auth-init:メソッド、URI、メッセージボディでダイジェスト生成 #### 9.8.3 WSSE認証 HTTP1.1標準外の認証方法である。AtomPubなど、上記の両認証が使えない場合に利用される。 WS-Security-UsernameTokenという認証方式がベースとなっている。 クライアントはパスワードとnonce、日時情報を用意し、ハッシュ値を求めてパスワードダイジェストを作成する。 ハッシュ関数利用のため安全性は高いが、サーバにパスワードを保持する必要がある。BasicとDigestの中間的な認証方式である。 ### 9.9 キャッシュ **一度取得したリソースをローカルストレージに蓄積しておくことで、再読み込みを迅速に行う**ための仕組みである。 複数のキャッシュ用ヘッダが用意されている。 * Pragma:キャッシュ不可を表す。 * Expires:キャッシュは期限つきであることを表す。日時の項目で紹介の通り、有効期限が表示される。 * Cache-Contorol:HTTP1.1で追加された、キャッシュ取得の詳細指定を行うヘッダ。上記のヘッダの両方の役割を果たし、より細かくキャッシュを制御できる。相対的な期間指定時に有効である。 #### 9.9.1 条件付きGET キャッシュの直接利用は困難でも、再利用できる可能性があるのが、条件付きGETである。 * If-Modified-Since:更新されているかどうかを確認する。304 Not-Modifiedが帰れば、変更されていないことがわかる。 * If-None-Match:ミリ秒単位の更新をキャッチしたい場合に、Etagヘッダの値を取得することで、比較可能になる。 ### 9.10 持続的接続 HTTP1.1の大きな新機能である。1画面の表示に様々なリクエストが送信される場合、従来はリクエストを送っては切断を繰り返して逐次実行していたため、動作が遅くなりがちであった。 そこで、Keep-Arriveヘッダにより、まとめて接続し続けることができるようになった。これにより**リクエストのパイプライン化**が実現し、処理速度が大幅に向上した。 ### 9.11 その他のヘッダ * Content-Disposition:サーバがクライアントに対し、リソースのファイル名を提示するために利用するレスポンスヘッダ。ファイル名の取得に便利だが、ブラウザごとにエンコーディング方式が異なるため、日本語文字の取得には注意が必要である。 * Slug:AtomPubの拡張ヘッダの一つ。新しく生成するURIのヒントとなる文字列をサーバに提示できる。なお、エンコーディング方式は%エンコーディングである。 ###### tags: `読書`