「Webを支える技術」を読んで
よく良書として挙げられている「Webを支える技術 HTTP、URI、HTML、そしてREST」を読んだのでまとめ。
HTMLは学習済なのでとばした。それを言ったらHTTPだって勉強済なんだけど...理解できてないのでまとめました。主な目的はRESTを理解すること。
- REST(Representational State Transfer)とは
- URI(Uniform Resource Identifier)
- HTTPの基本
- HTTPメソッド
- ステータスコード
- HTTPヘッダ
- キャッシュ
- Atom
- JSON
- リソース設計
REST(Representational State Transfer)とは
クライアント/サーバから派生したWebのアーキテクチャスタイル。以下の6つを組み合わせたネットワークシステムのアーキテクチャスタイル。
- クライアント/サーバ:クライアントとサーバで処理を分離する
- ステートレスサーバ:クライアントのアプリケーション状態をサーバ側で管理しない
- キャッシュ(Cache):クライアントとサーバ間の通信量を減らす
- 統一インターフェース:インターフェースを固定する
- 階層化システム:システムを階層に分離する
- コードオンデマンド:プログラムをサーバからクライアントにダウンロードし実行する
URI(Uniform Resource Identifier)
URIの構文
例:http://user:pass@blog.example.jp:8000/search?q=test&debug=true#n10
①http
:URIスキーム
②user:pass
:ユーザ情報
③blog.example.jp
:ホスト名
④8000
:ポート番号
⑤/search
:パス
⑥q=test&debug=true
:クエリパラメータ
⑦#n10
:URIフラグメント
ベースURI
相対URIの起点となるURIのことをベースURIという。相対URIを絶対URIに変換することを「相対URIを解決する」という。
ベースURIは直感的に指定する方法と、HTMLやXMLの中で明示的に指定する方法がある。
使用できる文字と%エンコーディング
URIの仕様では、アルファベット・数字・記号のいわゆるASCII文字が使えると定められている。
日本語などのASCII以外の文字をURIに入れるときには、「%16進数」という形になるようUTF-8でエンコードされる。(%エンコーディングという)
URIの設計指針
- URIにプログラミング言語依存の拡張子を利用しない(
.pl
、.do
、.jsp
など) - URIに実装依存のパス名を利用しない(
cgi-bin
、servlet
など) - URIにプログラミング言語のメソッド名を利用しない
- URIにセッションIDを含めない
- URIはそのリソースを表現する名詞である
その他設計テクニック
- URIをやむを得ず変更したいときはリダイレクトすること
- 言語を指定する拡張子はOK(
http://example.jp2020.08/31/.press.en
など) - 複数パラメータを表現するにはセミコロンかカンマを使ったマトリクスURIを使う(地図など)
HTTPの基本
HTTPとは
RESTの重要な特徴である統一インターフェース、ステートレスサーバ、キャッシュなどを実現しているWebの基盤となるプロトコル。
TCP/PIとは
インターネットの基盤を構成する重要なネットワークプロトコル。以下の通り階層型になっている。
リクエストとレスポンス
Webサイトにアクセスしたときに行われること
<クライアント側>
①リクエストメッセージの構築
②リクエストメッセージの送信
③(レスポンスが返るまで待機)
④レスポンスメッセージの受信
⑤レスポンスメッセージの解析
⑥クライアントの目的を達成するために必要な処理
<サーバ側>
❶(リクエストの待機)
❷リクエストメッセージの受信
❸リクエストメッセージの解析
❹適切なアプリケーションプログラムへの処理の委譲
❺アプリケーションプログラムから結果を取得
❻レスポンスメッセージの構築
❼レスポンスメッセージの送信
HTTPメッセージ
<構造>
◆リクエストメッセージ
<例>
GET /test HTTP/1.1
Host: example.jp
GET search?q=test&debug=true HTTP/1.1
Host: example.jp:8080
1行目:リクエストライン
メソッド(GET)、リクエストURI(/test)、プロトコルバージョン(HTTP/1.1)
リクエストURIは絶対URIになることもある。
2行目:ヘッダ
名前(Host): 値(example.jp)
ヘッダのあとにボディが続くこともある。
◆レスポンスメッセージ
<例>
HTTP/1.1 200 OK
Content-Type: application/xhtml+xml; charset=utf-8
<html xmlns="http://www.w3.org/1999/xhtml">
...
</html>
1行目:ステータスライン
プロトコルバージョン(HTTP/1.1)、ステータスコード(200)、テキストフレーズ(OK)
2行目:ヘッダ
ヘッダ→空行→ボディ となる。
HTTPのステートレス性
HTTPはステートレスなプロトコルである。FTPはステートフルなプロトコルの代表例である。
◆ステートフル
・やりとりが簡潔
・サーバがクライアントのそれまでの注文(セッション状態、アプリケーション状態)を覚えている
・クライアントの数が増えるとセッション状態を覚えておくことが難しくなる
◆ステートレス
・やりとりが冗長
・クライアントは毎回すべての注文(自己記述的メッセージ)を繰り返す
・クライアントが送信するデータ量が多くなる
・認証などのサーバに負荷がかかる処理を繰り返してしまう
・通信トラブルのときにリクエストが処理されたかわからない
HTTPメソッド
8つのメソッド
HTTPで定義されているメソッドは以下の8つ。
メソッド | 意味 |
---|---|
GET | リソースの取得 |
POST | 子リソースの作成、リソースへのデータ追加、その他の処理 |
PUT | リソースの更新、リソースの作成 |
DELETE | リソースの削除 |
HEAD | リソースのヘッダ(メタデータ)の取得 |
OPTIONS | リソースがサポートしているメソッドの取得 |
TRACE | 自分宛にリクエストメッセージを返す(ループバック)試験 |
CONNECT | プロキシ動作のトンネル接続への変更 |
HTTPメソッドとCRUD
GET, POST, PUT, DELETEはCRUDという性質を満たす代表的なメソッドである。
CRUD名 | メソッド |
---|---|
Create | POST/PUT |
Read | GET |
Update | PUT |
Delete | DELETE |
POSTとPUTの使い分け
POSTはクライアントはリソースURIを指定できない。URIの決定権はサーバ側にある。Twitter向き。
PUTはクライアントがURIを決める。wikiなどに向く。
POSTでPUT/DELETEを代用する方法
HTMLのフォームで指定できるメソッドがGETとPOSTの2つであることもあり、この2つのメソッドしか使用を許可されていない場合もある。
このような状況の時にサーバにPUTやDELETEを伝える方法が2つある。
- _methodパラメータを用いる
フォームの隠しパラメータ(hidden)に_methodというパラメータを用意し、そこに本来送りたかったメソッドの名前を入れる - X-HTTP-Method-Overrideヘッダ
_methodパラメータはPOSTの内容がXMLなどの場合は利用できない。このような場合にはX-HTTP-Method-Overrideヘッダを用いてX-HTTP-Method-Override: PUT
と記述する
べき等性と安全性
べき等:ある操作を何回行っても結果が同じこと
安全性:操作対象のリソースの状態を変化させないこと
メソッド | 性質 |
---|---|
GET, HEAD | べき等かつ安全 |
PUT, DELETE | べき等だが安全でない |
POST | べき等でも安全でもない |
使い方によってはべき等でなくなる場合もある。
他のメソッドでできることをPOSTで実現しようとしないこと。
ステータスコード
ステータスコードの分類
ステータスコードは3桁の数字で、先頭の数字によって5つに分類される。
分類 | 意味 |
---|---|
1xx | 処理中 |
2xx | 成功 |
3xx | リダイレクト |
4xx | クライアントエラー |
5xx | サーバエラー |
よく使われるステータスコード
200 OK
:リクエスト成功
リクエストが成功したことを示す201 Created
:リソースの作成成功
リソースを新たに作成したことを示す。POSTとPUTのレスポンスとして返される。301 Moved Permanently
:リソースの恒久的な移動
指定したリソースが新しいURIに移動したことを示す。古いURIを保ちつつ新しいURIに移行する際に用いる。303 See Other
:別URIの参照
リクエストに対する処理結果が別のURIで取得できることを示す400 Bad Request
:リクエストの間違い
リクエストの構文やパラメータが間違っていたことを示す。ほかに適切なクライアントエラーを示すステータスコードがない場合にも用いる。401 Unauthorized
:アクセス権不正
適切な認証情報を与えずにリクエストを行ったことを示す404 Not Found
:リソースの不在
指定したリソースが見つからないことを示す500 Internal Server Error
:サーバ内部エラー
サーバ側に何らかの異常が生じていて正しいレスポンスが返せないことを示す。ほかに適切なサーバエラーを示すステータスコードがない場合にも用いる。503 Service Unavailable
:サービス停止
サーバがメンテナンスなどで一時的にアクセスできないことを示す
ステータスコードは正しく使おう。
HTTPヘッダ
MIME(Multipurpose Internet Mail Extensions)メディアタイプ
メッセージでやりとりするリソースの表現の種類を指定するのがMIMEメディアタイプである。HTTPではそのうちのContent-Typeヘッダなどいくつかを利用する。
Content-Typeヘッダ
メッセージのボディの内容がどのような種類なのかをメディアタイプで表す。
<例>
Content-Type: application/xhtml+xml; charset=utf-8
application/xhtml+xml
がメディアタイプ。/
の左側をタイプ、右側をサブタイプと呼ぶ。タイプは増やすことはできないがサブタイプは比較的自由に増やすことができる。登録済のタイプとサブタイプの一覧はIANAが管理している。
charsetパラメータ
先ほどの例ではこのXHTML文書をUTF-8でエンコードしていることを示している。
charsetパラメータは省略可能だが、タイプがtextの場合は注意が必要であるため、必ずcharsetを付けるほうが望ましい。
言語タグ
charsetパラメータは文字エンコーディング方式を指定するものだが、リソース表現の自然言語を指定するContent-Languageヘッダもある。
<例>
Content-Language: ja-JP
ja
が日本語の言語コード、JP
は地域コード。
コンテントネゴシエーション
クライアントと交渉して決める手法をコンテントネゴシエーションという。
- Acceptヘッダ
クライアントが自分の処理できるメディアタイプをサーバに伝える - Accept-Charsetヘッダ
クライアントが自分の処理できる文字エンコーディングをサーバに伝える - Accept-Languageヘッダ
クライアントが自分の処理できる言語タグをサーバに伝える
Content-Lengthメッダ
メッセージがボディを持っている場合、基本的にはContent-Lengthヘッダを利用して、そのサイズを10進数のバイトで示す。
チャンク転送
動的に画像を生成するようなWebサービスの場合、ファイルサイズが決まるまでにレスポンスが返せないのでは応答性能が低下してしまう。このときにTransfer-Encodingヘッダにchunkedを指定すると、最終的なサイズがわからないボディを少しずつ転送できるようになる。
Transfer-Encoding: chunked
認証
主流のHTTP認証方式はBasic認証とDigest認証がある。また、Web APIではWSSE(WS-Security Extension)というHTTP認証の拡張仕様を利用することもある。
◆Basic認証
ユーザ名とパスワードによる認証方式。
ユーザ名とパスワードはAuthorizationヘッダに入れてリクエストごとに送信する。Authorizationヘッダの内容は認証方式(Basic)に続けてユーザ名とパスワードを:
で連結しBase64エンコードした文字列になる。エンコーディングは簡単にデコード可能であるため、Basic認証を利用する場合は、その程度のセキュリティ強度で良いのか、SSLやTLSを使ってHTTPS通信するのかを検討する必要がある。
◆Digest認証
Basic認証よりもセキュアで複雑な認証方式。
サーバ上にパスワードのハッシュ値を補完しておけばいいのでパスワードそのものをサーバに預けなくて良い。ただしDigest認証はパスワードを暗号化するだけで、メッセージ自体は平文でネットワーク上を流れるため注意が必要。
キャッシュ
クライアントはサーバから取得したリソースがキャッシュ可能かどうかを調べ、可能な場合はローカルストレージに蓄積する。リソースがキャッシュ可能かどうか、その有効期限がいつまでなのかはPragma、Expires、Cache-Controlヘッダを用いてサーバが指定する。
Pragmaヘッダ
Pragmaヘッダに指定できる値はno-cacheのみ。
pragma: no-cache
Expiresヘッダ
Expiresはキャッシュの有効期限を示すヘッダ。
<例>
Expires: Tue, 1 Sep 2020 17:00:00 GMT
Cache-Controlヘッダ
複雑な指定ができる。
pragma: no-cache
これは
Cache-Control: no-cache
と等しい。
有効期限を指定する場合、現在からの相対時間を設定することができる。
Cache-Control: max-age: 86400
これは86,400秒、すなわち現在から24時間キャッシュが有効であることを示している。
条件付きGET
クライアントがExpiresやCache-Controlヘッダを検証した結果、ローカルキャッシュをそのまま再利用できないと判断した場合でも、条件付きGETを送信すればキャッシュを再利用できる可能性がある。
条件付きGETは、そのリソースがLast-ModifiedヘッダまたはETagヘッダを持っているときに利用できる。
Atom
Atomとは
RSSの仕様が乱立したため、標準フォーマットを策定する目的で作られたXMLフォーマット。RSSは主にブログの新着情報を伝えるフィードの目的で使われていたが、Atomはブログだけでなく検索エンジンや写真管理などさまざまなWeb APIとして利用できる。
Atomの構成要素
Atom Publishing Protocol
Atom:データフォーマットの規程(フィード、エントリ)
AtomPub:Atomを利用したリソース編集プロトコルの規程
AtomPubはAtomが規程したリソースの編集、いわゆるCRUD操作を実現するためのRESTスタイルに基づいたプロトコル。
AtomPubを使えば、ブラウザ以外のWebクライアントからブログを投稿したり、システム同士を連携したりすることが簡単にできるようになる。
<AtomPubに向いていないWeb API>
・Cometを利用するようなリアルタイム性が重要なAPI
・映像のストリーム配信など、HTTP以外のプロトコルを必要とするAPI
・データの階層構造が重要なAPI
・「タイトル」「作者」「更新日時」など、Atomほーマットが用意するメタデータが不要なAPI
JSON
JSON(JavaScript Object Notation)とは
RFC4627が規程するJavaScriptの記法で記述できるデータ記述言語。多くの言語がライブラリを用意しているため、プログラミング言語間でデータを受け渡しできる。
データ型
JSONに組み込みで用意されているデータ型は次の6つ。
- オブジェクト
- 配列
- 文字列
- 数値
- ブーリアン
- null
JSONには組み込み型としての日時型がないため、日時を表現するときは開発者側で規程を準備しなければならない。最も単純なのはUNIX時間を数値として表現する方法である。
クロスドメイン通信
JSONでリソース表現を提供する副次的効果としてJSONP(JSON with Padding)を利用できる。
Ajaxで用いるXMLHttpRequestというJavaScriptのモジュールは、セキュリティ上の制限からJavaScriptファイルを取得したのと同じサーバとしか通信できない。単一のドメインとしか通信できないことは大きな制約である。
JSONPは、HTMLのscript要素を用いてブラウザのセキュリティ制限を受けないようにし、クロスドメイン通信(ドメインをまたがった通信)を実現する手法である。
リソース設計
リソース設計とは
リソース設計とは、クライアントとサーバ間のインターフェースの設計、つまりWebサービスやWeb APIの外部設計のことである。
リソース設計の指針として唯一存在するのは、「リソース指向アーキテクチャ」の設計アプローチである。
リソース指向アーキテクチャの手法
①Webサービスで提供するデータを特定する
②データをリソースに分ける
各リソースに対して次の作業を行う。
③リソースにURIで名前を付ける
④クライアントに提供するリソースの表現を設計する
⑤リンクとフォームを利用してリソース同士を結びつける
⑥イベントの標準的なコースを検討する
⑦エラーについて検討する
他のリソース設計方法
以下の既存の設計手法で得られた成果物をもとにリソースを設計する方法もある。