書籍『Webを支える技術』まとめ
(2021/05/09~執筆中)
書籍情報
出版 2010年
著者 山本陽平
この記事について
Webまわりの基礎知識まとめ。
本の内容を後でぱっと思い出せるよう、個人的に大事だと思ったところをざっとまとめておく。
書籍がやや古い(HTTP1.0の時代)こともあり詳細な仕様ではなく設計思想など概念的な話が多めになります。
1部 Web概論
概要
Webが持つ技術的特徴について。HTTP、URI、HTMLがどのような原則で設計されているのか。
Webの用途
- Webサイト
- ユーザーインターフェースとしてのWeb(ルーターやプリンタなどのデバイスの設定画面)
- プログラム用インターフェースとしてのWeb(データフォーマットとしてXMLやJSONを使う)
HTTP、URI、HTTP
Webを支える最も基本的な技術。
- HTTP( Hypertext Transfer Protocol)
- URI( Uniform Resource Identifier)
- HTML (HyperText Markup Language)
これらについて以後詳しく見ていく。
なお、Webは情報システムとして以下の2つの側面を持つ
1.ハイパーメディア
テキストや画像、音声、映像など様々なメディアをハイパーリンクで結び付けて構築したシステムのこと。
書籍や映画などが線形的に先頭から順に読んだり見たりするのに対して、ハイパーメディアは非線形的にユーザが自分でリンクを選択して情報を取得する。
2.分散システム
中央コンピュータがすべてを処理する「集中システム」に対して、複数のコンピュータを組み合わせて処理を分散させる形式を「分散システム」という。
Web誕生
Web以前のハイパーメディア
- 1945年 ハイパーメディアの起源 - Memex構想(情報検索システムの論文)
- 1965年 ハイパーメディアの誕生 - テキストに加え音声や動画など多様なメディアを相互にリンクさせた概念
- 1969年 インターネットの起源 - ARPANET
- 1987年 実用的なハイパーメディア - HyperCard(Apple)
複雑で多機能を目指す方向性だった。
Web以前の分散システム
RPC(Remote Procedure Call)リモートのサーバで実行しているプログラムをクライアント側から呼び出せる。ネットワークごしの関数呼び出し。(今もNFSとかで使われてるらしい)
問題点としては 、
サーバー上にクライアントのアプリケーション状態を保存して、かつそれをサーバー間で共有しなけなかったり、言語ごとのデータ型の違いを吸収できなかったり、関数の呼び出しでネットワークのオーバーヘッドが大変だった。実用的にはイントラネット内が限界。
Web誕生
- 1990年 スイスのCREN研究所のTim Verners-LeeがWebの提案書を書く- ブラウザとサーバを完成させる
- 1993年 イリノイ大学NCSAがブラウザMosaicを公開(IE,FFの源流)
Webの特徴としては、
- (+)インターネットを使ったハイパーメディア
- (+)不特定多数の情報をリンクさせ合える
‐ (+)特定のハードやOSに依存しない - (-)情報の集中管理は難しい
- (-)単方向リンクのためリンクのためリンク切れを起こしやすい
Webの標準化
Web以前のインターネット標準はすべてIETF( Internet Engineering Task Force)のRFC( Request for Comments)として定められてきたが、急速な普及に対応しきれず、各社ばらばらの実装を進めてしまった(ブラウザ対応という言葉の源流)。
2000年 カリフォルニア大学院生のRoy FieldingがWebのアーキテクチャスタイルを「REST(Representation State Transfer)」と名付けた論文をを発表した。RESTの普及と並行してWebがインターネット世界を席巻していく。
アーキテクチャスタイル
アーキテクチャスタイルは抽象度の高い概念。例としては以下
概念 | 例 |
---|---|
アーキテクチャスタイル | REST |
アーキテクチャ | ブラウザ、サーバ、プロキシ、HTTP、URI、HTML |
実装 | Apache、Firefox、IE |
リソース
RESTにおける重要な概念
- 「リソース」 (東京の天気予報、Webページ、吉祥寺駅の写真etc)
- 「アドレス可能性」リソースを簡単に指し示せる(リソースの名前としてのURI)
- 「リソースの表現」サーバとクライアント間でやりとりする具体的なデータ
RESTの構成
RESTは複数のアーキテクチャスタイル(以下の6つ)の複合体として構成される。
これらを必要に応じて実装していく。
-
クライアント/サーバ
HTTPプロトコルでクライアントとサーバが通信する。
クライアントはサーバにリクエストを送り、サーバはそれに対してレスポンスを返す。
クライアントUIとして、サーバはデータストレージとして機能する。 -
ステートレスサーバ
クライアントのアプリケーション状態をサーバーが管理しない。
サーバはレスポンス後すぐにリソースを解放できる。
(⇔Cookieによるセッション管理) -
キャッシュ
一度取得したリソースをクライアント側で使いまわす。通信量を減らす。 -
統一インターフェース
HTTP1.1ではGETやPOSTなど8個のメソッドで操作を行うように、URIで指し示すリソースに対する操作を限定的なインターフェースで行う。 -
階層化システム
統一インターフェースのおかげで、クライアントとサーバの間にロードバランサーを入れて負荷分散したり、プロキシを入れてアクセス制限したり、システムを階層に分離できるようになった。これを階層化システムという。 -
コードオンデマンド
コードをサーバからダウンロードしクライアント側で実行するアーキテクチャ。
JavaScriptとかJaveアプレットとか。クライアントを後から拡張できる。
RESTful
RESTらしいこと。
WebはRESTという分散ネットワークシステムの為の理論のおかげで普及した。
2部 URI
概要
URIの構文とその意味。WebサービスやWeb APIにおけるURI設計について。
URIとはリソースを統一的に識別するIDのこと。
URIを使うとWeb上全てのリソースを一意に示せる。
↓公式ドキュメント的なやつ、そのうち目を通そうと思う。
URIの仕様
URIの構成
URIの例①
http://example.jp/post/1
URIの構成パーツは、
- URIスキーム :http - 基本的にはプロトコル
- ホスト名 :example.jp - ドメイン名またはIPアドレス
- パス :/post/1 - ホスト内でのリソースを階層で表す
URIの例②
http://seiji:pass@example.jp/search?q=test&debug=true#n10
URIの構成パーツは、上記に加えて
- ユーザ情報 :nihei:pass - リソースにアクセスする際に利用するユーザー名とパス
- ポート番号 :8000 - このホストにアクセスるときのプロトコルで用いるTCPポート番号
- クエリパラメータ :q=test&debug=true - 例えば検索の値など動的にURIを作成する。&で連結
- URIフラグメント :#n10 ‐ リソース内部のさらに細かい部分を特定するときに使う
URIと文字
URIで使える文字はASCII文字
- アルファベット: A-za-z
- 数字: 0-9
- 記号: -.~:@!$&'()
※日本語を入れるときは%エンコーディングという方式を使う。
※文字エンコードが異なると%エンコード結果が変わってくるので無難なUTF-8を使うのがよい
URIの設計
クールなURIは変わらない
実際問題として、URIは変わってしまうことがあるのだが、「変わりにくい」設計は可能。
- プログラム言語に依存した拡張子やパスを含めない(.plとか/servletとか)
- 実装依存のパス名を利用しない(/LoginServletみたいなjavaの大文字文化)
- メソッド名やセッションIDを含めない(システムをリファクタリングしてメソッド名変えたら使えない)
- リソースを表現する名詞にする(HTTPはHTTPメソッドが動詞を表現してる)
悪い例
http://example.jp/servlet/LoginServlet
良い例
http://example.jp/login
3部 HTTP
HTTPプロトコルの仕様。WebサービスやWeb API開発におけるHTTPの利用法。
HTTPはハイパーテキストだけでなく静止画、音声、動画、JSプログラム、PDFファイルなどコンピュータで扱えるデータであれば何でも転送できる。
現在はHTTP/2がメインとなっている。(書籍発刊時はHTTP/1)
HTTPの基本
TCP/IP
インターネットのネットワークプロトコル
4階層からなる
- ネットワークインタフェース層
物理的なケーブルやネットワークアダプタに相当 - インターネット層
IPが相当。パケット単位で特定のIPアドレスに向けてデータを送り出す - トランスポート層
TCPが相当。接続先の相手にコネクションを張りデータ転送を保証する。
TCPで接続したコネクションで転送するデータが、どのアプリケーションに渡るか決定するのが「ポート番号」。 - アプリケーション層
HTTP、NTP、SSH、SMTP、DNSに相当。
リクエストとレスポンス
HTTPではクライアントが出したリクエストをサーバで処理してレスポンスを返す。
リクエスト/レスポンス型のプロトコル。
クライアントはレスポンスが帰るまで待機する(HTTPが同期型のため)。
クライアントの動き
- リクエストメッセージの構築
- リクエストメッセージの送信
- (レスポンス待ち)
- レスポンスメッセージの受信
- レスポンスメッセージの解析
- クライアントの目的を達成するために必要な処理
サーバの動き
- (リクエストの待機)
- レスポンスメッセージの受信
- レスポンスメッセージの解析
- アプリケーションプログラムへの処理の移譲
- アプリケーションプログラムから結果を取得
- レスポンスメッセージの構築
- レスポンスメッセージの送信
HTTPメッセージ
- リクエストメッセージ
- レスポンスメッセージ
(※後でHTTPメッセージの詳細をみてみる記事を書く予定)
構造としてはこうなる
スタートライン(リクエストライン/ステータスライン)(1行目)
ヘッダ(メタデータ)
(空行)
ボディ(リソースの表現など)
ステートレスとステートフル
HTTPはステートレスなプロトコルとして設計されている。
ステートレスとはサーバがクライアントのアプリケーション状態を保存しない制約のこと。
ステートレスにするとクライアント/サーバ間のやり取りが冗長になる欠点があるが、サーバ側のシステムは単純になる。反対にステートフルにするとアプリケーションの状態を保持できるためやり取りは簡潔になるが、サーバ間でクライアントのアプリケーション状態を共有していなければならず、スケールアウトが難しくなるなどの欠点がある。
HTTPメソッド
HTTPのメソッドは8つのみ。
HTTPメソッドの役割はクライアントが行いたい処理をサーバに伝えること。
目的によって以下を適切に使い分ける。
- GET(リソース取得)
- POST(リソース作成、データ追加、その他)
- PUT(リソース更新、リソース作成)
- DELETE(リソース削除)
- HEAD(リソースのヘッダの取得)
- OPTIONS(リソースがサポートするメソッドの取得)
- TRACE(自分宛てにリクエストメッセージを返す)
- CONNECT(プロキシ動作のトンネル接続への変更)←?
冪等性と安全性
- 冪等性
ある操作を何回行っても結果が同じであること
例)3×0=3×0×0×0 - 安全性
操作対象のリソースの状態を変化させないこと
メソッドの誤用
上記の冪等性、安全性を踏まえたうえで、HTTPメソッドの性質は下記となる。
メソッド | 性質 |
---|---|
GET、HEAD | 冪等かつ安全 |
PUT、DELETE | 冪等だが安全でない |
POST | 冪等でも安全でもない |
よって下記のようなGETの使い方は推奨されない
GET /resources/1/delete HTTP/1.1
削除の為にGETメソッドを用いるとGETの性質である冪等かつ安全が損なわれる。
常識を無視したAPI設計などは分かりづらいので気を付ける。
=====================================
余談だが、laravelのRoute::resourceでCRUDを生成したとき、このあたりの使い分けがちゃんとできてる。以下自分のアプリのroute:listから一部抜粋した。少し情報を削ったがそのURIとメソッドで何が行われるかすぐに理解できる。
+-----------+-------------------------+
| Method | URI |
+-----------+-------------------------+
| GET|HEAD | / |
| GET|HEAD | articles |
| POST | articles |
| GET|HEAD | articles/create |
| GET|HEAD | articles/{article} |
| PUT|PATCH | articles/{article} |
| DELETE | articles/{article} |
| GET|HEAD | articles/{article}/edit |
+-----------+-------------------------+
ステータスコード
レスポンスメッセージの1行目ステータスラインに記述される。
ステータスコードは3桁の数字からなり、以下の5つに分類される。
- 1xx:処理中
- 2xx:成功
- 3xx:リダイレクト
- 4xx:クライアントエラー
- 5xx:サーバエラー
もっと詳しく見る場合は以下
https://developer.mozilla.org/ja/docs/Web/HTTP/Status
ステータスコードを自分で設定する必要がある場合は、HTTPメソッドと同様に正しく使うことをここをがける。
エラーを200 OKで返してボディでエラーメッセージを返すみたいな実装をすると、正常処理としてボディを表示してしまうなど問題が発生する可能性があるので注意する。
HTTPヘッダ
HTTPメッセージのボディに対する付加的な情報(メタデータ)
メタデータとは一般に、あるファイルに対する編集者、保存場所、データサイズのような情報に対する情報のこと。HTTPにおいてもメッセージに対してメタデータが存在しHTTPヘッダで表現できる。
リクエストに使われるヘッダ、レスポンスに使われるヘッダ、両方に使われるヘッダがある。
例えば以下のようなヘッダがある
- 日時
- Date:メッセージを生成した日時
- Expires:レスポンスをキャッシュできる期限
- メディアタイプ
- Content-Type:メッセージのボディの内容
- Content-Type:application/xhtml+xml; charset=utf-8
メディアタイプ(タイプ/サブタイプ) - タイプにはtext,image,multipartなどがある
他にもたくさんヘッダがある。
- Content-Type:application/xhtml+xml; charset=utf-8
- Content-Type:メッセージのボディの内容
ヘッダはメソッドやステータスコードと組み合わせて、認証やキャッシュなどの機能を実現できる
キャッシュや認証については別記事を書く予定。
4部 ハイパーメディアフォーマット
HTML、microformats、Atom、JSONについて。(この部は省略)
5部 Webサービスの設計
概要
WebサービスやWeb API開発におけるHTTPやURIの設計(リソース設計)について
補足 その他参考
RFCってなんぞやってときは
Discussion