Real World HTTPを読んだ (2章のみ)
前回 (Real World HTTPを読んだ (1章のみ) - 将軍の備忘録) に引き続き、 個人的に気になったところを書いていきます。
Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術
- 作者: 渋川よしき
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/06/14
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
コンテントネゴシエーション
- サーバとクライアントは、別々に開発されているため、期待している形式が一致するとは限らない
- 1リクエストの中でサーバとクライアントがお互いのベストな設定を共有する仕組み
- ネゴシエーションにはヘッダを使う
以下、表を引用
リクエストヘッダー | レスポンス | ネゴシエーション対象 |
---|---|---|
Accept | Content-Type | MIMEタイプ |
Accept-Language | Content-Language/htmlタグ | 表示言語 |
Accept-Charset | Content-Type | 文字のキャラクタセット |
Accept-Encoding | Content-Encoding | ボディの圧縮 |
こちらのブログでキャラセットについても改めて確認。
ファイルの種類の決定
以下のようなリクエストヘッダ(Accept)だった場合
image/webp */*;q=0.8
- qは、品質係数と言われ、0から1まで指定する。デフォは1。
- Webサーバは、WebPに対応していれば、WebPを返す
- Webサーバが、WebPに対応していなければ、他のフォーマット(優先度0.8)をサーバーに要求
表示言語の決定
以下のようなリクエストヘッダの場合
Accept=Language: en-US,en;q=0.8,ja:q=0.6
- en-US,en,jaの優先順位でリクエスト送る。
- あまり使われておらず、
<html lang="ja">
のようにHTMLタグの中で返しているページが多い
キャラクターセットの決定
以下のようなリクエストヘッダを送信するが、
Accept-Charset: UTF-8,Shift_JIS;q=0.7,*;=0.3
- どのモダンブラウザも
Accept-Charset
を送信していない。 - 理由はおそらくどのブラウザも全てのキャラクターセットを内包しており、ネゴシエーションする必要がないからと想像される
- キャラクターセットは、MIMEタイプと一緒に
Content-Type
ヘッダーに格納される
圧縮による通信速度の向上
Accept-Encoding: deflate, gzip
- curlコマンドは、--compressedオプション
- Googleがgzipより効率が良い圧縮フォーマット Brotli の実装を公開
br
を指定してリクエストを送り、サーバが対応していればBrotli
による高速化が行われる- クライアント、もしくはサーバが
Brotil
に対応していなければ、別のエンコーディング(たぶんgzip)のフォールバックされる
クッキー
- クッキーは、ウェブサイトの情報をブラウザ側に保存する仕組み。
- サーバ → クライアントに「これを保存しといて」という指示を出す
- 例)最終アクセス日時と時間
Set-Cookie: LAST_ACCESS_DATE=Jul/31/2016 Set-Cookie: LAST_ACCESS_TIME=12:04
- クライアントはこれをローカルのストレージに保存しておき、次回同じURLアクセスする時にリクエストヘッダーに加えて送る
- HTTPはステートレスだがクッキーを使うことであたかもサーバーが状態を保持したステートレスであるかのように見せる
- クッキーの用途
- 無くなっても問題のない情報
- サーバ側の情報から復元できる情報
- 容量は4キロバイト
secure
を付与すればHTTPS通信のみ、HTTPの場合は平文で送受信する。パスワードとか要注意- クッキーには属性がいくつか定義されている
- Expires, Max-Age 、Domain属性、Path属性、Secure 属性、HttpOnly 属性、SameSite 属性
認証とセッション
- Ruby on Railsのデフォルトセッションストレージは、クッキーを使ったデータ保存。
- クライアントには、電子署名済みのデータを送り、クライアントがサーバにクッキーを再送することサーバは署名を確認する。
- 署名も確認もサーバ側で行うので、クライアント側は一切鍵をもたない
プロキシ
- HTTPなどの通信を中継したり、さまざまな付加機能(圧縮したり、キャッシュしたり) をよろしくやってくれる仕組み
- プロキシとゲートウェイの違い
- プロキシ:通信の内容を理解する。必要におうじてコンテンツを改変したり、サーバに変わって応答する
- ゲートウェイ:通信内容をそのまま転送する。内容の改変もやらない
キャッシュ
- 例えばすでにアクセスしてダウンロード済みのコンテンツの内容に変化がなければ、サーバからのダウンロードを制御し、それによってパフォーマンスをあげる仕組み。
更新日時のよるキャッシュ
- 例えば以下のようなレスポンスを含めたとする
Last-Modified: Wed, 08 Jun 2016 15:23:45 GMT
- ウェブブラウザがキャッシュ済みURLを再度読み込む際、日時をそのままヘッダーに入れてリクエストする
If-Modified-Since: Web, 08 Jun 2016 15:23:45 GMT
- 次にWebサーバは、受け取った日時とサーバ上のコンテンツ日時を比較し、変更があれば通常通りレスポンスを返し、変更がなければ
304 Not Modified
(ボディはない)を返す。
Expires
- 更新日時を使ったキャッシュの場合、キャッシュの有効性を確認するための通信が発生してしまう
- その通信自体をなくしてしまおうというのが、
Expires
- 例
Expires: Fri, 05 Aug 2016 00:11:22 GMT
- クライアントは、この期限内であれば新鮮と判断し、強制的にキャッシュを利用
- 期限がすぎていれば新鮮ではないと判断
- 期限内で一切問い合わせされなくなるので、要注意
Pragma: no-cache
- クライアントからプロキシサーバに指示を送ることもある
- 唯一仕様に定義されているのが,
no-cache
- 「リクエストしたコンテンツがキャッシュされていたとしても、オリジンサーバまでリクエストを届けてほしい」という指示
Etag
- 上述のシーケンシャルな更新日時とは違って、ファイルに関連するハッシュ値を使って比較する
- サーバは、レスポンスに
Etag
ヘッダをつける - 2度目以降のダウンロード時にクライアントは
IF-None-Match
ヘッダにEtag
の値をつける - サーバは受け取った
Etag
とリクエストされたfairunoEtag
を比較する。 - Apache2.3.15、Nginx、h2oが付与するEtagの書式は、
更新日時 + ファイルサイズ
となっている。
Cache-Control
- 柔軟なキャッシュ制御が可能
- Expiresよりも優先される
- こちらのqiitaの記事がわかりやすかった
Vary
- 同じURLでもクライアントによって返す結果が異なることを示すヘッダ
- 例えば、ブラウザがスマホ用なのかPC用なのかとか
- この表示が変わる理由にあたるヘッダを列挙することで、それぞれにあったキャッシュを返すことができる
- 例)User-Agent, Accept-Languageの設定ごとにキャッシュする
Vary: User-Agent, Accept-Language
リファラー
- ユーザがどの経路からウェブサイトに到達したかをクライアントがサーバに送るヘッダ。
検索エンジン向けのコンテンツのアクセス制御
- クローラー向けのアクセス制御方法は、主に2つ
robots.txt
User-agent: * Disallow: /cgi-bin/ Disallow: /tmp
- HTMLのメタタグにも記述できる
<meta name="robots" content="noindex" />
サイトマップ
- ウェブサイトに含まれるページ一覧とそのメタデータを提供するXMLファイル
- robots.txtは
ブラックリスト
的に使うが、サイトマップはホワイトリスト
- クローラーはページを辿ってページを発見していく
- サイトマップは、robots.txtにも書ける
Sitemap: http://www/example.org/sitemap.xml
おしまい。