HTTPのバージョン
HTTP/1.1
1999年に策定されて長らくこれが主流だった。
ブラウザから同一のサーバへの接続数の推奨値は2ですが、主要なブラウザはWebページの表示速度を上げるために最大で6のTCPコネクションを同時に確立し、並列ダウンロードする実装を行っています。一つのユーザーで複数のソケットを消費してしまうのでサーバーへの同時接続数が減ります。
並列でタイムロスが発生する。
コネクションを確立したら、一つのリクエストに対して一つのレスポンスを返すという一連の流れを1リクエストずつこなしていきます。例えば複数画像ファイルを同時にダウンロードできない等同時処理ができないのでタイムロスが発生します。1.1にも並列で処理する機能であるHTTPパイプライニングという機能がありますが、期待するほど通信は効率化できなかったので採用には至りませんでした。
Keep-Alive
目的の通信が終わった後もTCPコネクションを一定時間維持し、連続した要求が来たときは前回の接続を再利用することで、毎回TCPコネクションを確立する無駄を省いています。
HTTP/2
2023年現在はWebサーバーでバージョンを指定しなければデフォルトがこのバージョンになります。
HTTP/1.1の後継として2015年に策定されました。Googleが開発したSPDYというプロトコルをほぼそのまま利用しています。一つのTCPコネクションのみを確立して、その中で一つのソケットのみ確立します。HTTP/1.1に比べると同時接続可能なユーザー数が増えます。
ヘッダフィールド名が全て小文字になった。
Cache-Controlが、cache-controlになるなど。サーバーサイドの実装などで影響を受ける可能性があります。(例:PHPなどでgetallHeaders()を使ってる場合など)
ストリームの採用
1つのTCPコネクションの中にハンドシェイク不要の仮想的なTCPソケットを複数作成し、それを用いて並列ダウンロードを実現する仕組みです。ブラウザ側では前の画像の処理終了を待つことなく次の画像の受信をすることが可能です。
これが登場する前はドメインシャーディングといったTCPコネクション数を稼いで高速化を行う手法も取られていたのですが、それはほぼ無意味になりました。
ヘッダ圧縮
HTTPSの必須化
サーバープッシュ
HTTP/3
2018年に策定された。2と3が近年急速に出てきた背景としては、Webページの複雑化によるもの。1.1では遅延が発生するようになってきてしまったのです。
HTTPリクエスト
リクエストライン
GETやHTTPのバージョンを指定します。
ヘッダ
Host
クライアントがサーバーに要求するドメイン名とポート番号です。
User-Agent
クライアントが使用しているWebブラウザアプリケーションのタイプです。
Accept-Encoding
コンテンツがどの圧縮アルゴリズムならクライアントが理解できるかを示しています。
Connection
Cookie
サーバーへのリクエストの際に自動でセットされます。多くのWebシステムではこれを用いてセッションを維持している。
ボディ
付けることも可能ですが、つけないことが多いです。
HTTPレスポンス
レスポンスヘッダの理解は配信の最適化には非常に重要です。
ステータスライン
HTTPのバージョンやリクエスト結果ステータスが格納されます。
ヘッダー
内容はオリジンサーバーや、Proxyサーバー、CDNサーバーで読み取りや生成、変更が自由にできます。
Date
いつHTTPレスポンスが生成されたかの日時が格納されます。
Content-Type
どのコンテンツタイプが格納されているかを示します。ブラウザはこれを見て形式や文字コードを判別します。
Cache-Control
max-age
キャッシュを制御するヘッダです。キャッシュを扱う上では非常に重要です。max-ageなどでキャッシュの有効期限を指定できます。(一般的にTTLと呼びます。)
なお、クライアントとオリジンは時刻が同期しているとは限らないのでクライアントがリクエストしたタイミング(Date)をもとにmax-ageを設定するのが一般的。
数式で表すと「Expires - Date = TTL(max-age)」になります。
例えば、Proxyを2台挟む場合はProxy1と2を通過する時間がmax-ageの秒数を超えてはいけないです。(1時間と指定されていたらProxy1、2を通過する合計時間が1時間を超えてはいけません。)
なので、プロキシを経由する際にTTLを消費していた場合は、末端のクライアント端末で使えるTTLはほとんど残らないケースもあります。その対策として、後述するs-maxageを指定することでCDNで使えるTTLとクライアント端末で使えるTTLを分割するという手法が有効です。
s-maxage
経路上の期限指定です。ProxyやCDNにとってのみ有効なキャッシュの期限になります。max-ageも同時に指定が可能で、max-ageが1800、s-maxageが3600だった場合はCDNでは3600秒キャッシュされて、末端のクライアントブラウザでは1800秒キャッシュが行われます。
stale-while-revalidate
キャッシュの期限が切れた際に何秒まで古いキャッシュを使って良いかの指定になります。2010年に策定されました。Chromeのサポートは2019年の75からです。
private/public
ここでprivateと指定すればprivateキャッシュになります。
なお、publicと指定するのは危険なので避けましょう。(ちなみに、sharedキャッシュにしたい場合は未指定でもそうなります。)、publicと指定するケースはかなり稀でAuthorizationヘッダーは通常キャッシュできないのですが検証目的で強制的にキャッシュしたい場合などに使える程度です。
Age
キャッシュされてからの経過時間です。具体的にはオリジンからのレスポンスをProxyがキャッシュしてからの期間です。Ageの経過時間が、Cache-Controlのmax-age以上であればキャッシュは有効期限切れと見なして再度リクエストが行われます。
Expires
期限切れを絶対時間で指定します。(Cache-Controlだと相対時間だった)
1 |
Expires: Thu, 12 Oct 2023 12:00:00 GMT |
x-
x-で始まるものは独自ヘッダと呼ばれる独自に使われる非標準ヘッダになります。
ボディ
HTMLが格納されます。
キャッシュとは?
一度ネット上で読み込んだデータをローカルに保存しておくことで再度データを表示する際に素早く表示することができるブラウザの機能です。Webアプリを実装する場合はセキュリティの問題でキャッシュは使わないこともあります。(ノーキャッシュ)
ただ、画像データなど第三者に流出しても問題ない内容であればこのキャッシュをうまく使っていくことが非常に重要になります。
キャッシュのメリット
クライアントからのリクエストを減らせるので転送量を抑えることができる。特に近年はAWSなどのクラウドサービスが転送量ベースで課金を行う方式を採用していることが多いので極めてブラウザキャッシュは重要です。
キャッシュのデメリット
- キャッシュされた情報が古い場合は最新情報が表示されない。
- ディスク上に個人情報が保存されてしまう。
キャッシュを有効活用する方法
基本的には、HTTPレスポンスヘッダのcache-controlで制御します。
例えば、1時間のキャッシュであれば「max-age=3600」と指定します。
なお、いくつかの条件を満たせばこの指定がなくても自動的にキャッシュを行います。(HTTP側の挙動)
ノーキャッシュの設定方法
ノーキャッシュにするには下記2つの方法があります。なお、HTTP/1.0とHTTP1.1では仕様が異なるので両方に対応してあげる必要があります。
- HTTPヘッダで制御する方法
- HTMLのmetaタグで制御する方法
HTTPレスポンスヘッダのcache-controlで制御する方法
no-storeと指定すればキャッシュを格納しないと指定できます。
ただ、エンドユーザーのクライアント端末では概ね問題ないのですが、もしCDNキャッシュを使っている場合CDNに受信した時にこれを解釈してくれないケースがあるので注意が必要です。本来キャッシュしてはいけないものをキャッシュできてしまうという事故にもつながります。
この事故を防ぐためには、まずは「private」、キャッシュを保存させないための「no-cache」、オリジンがダウンしていた場合にキャッシュされることを防ぐために「must-revalidate」を合わせて指定します。
no-cacheとの勘違いを避けること
ちなみに、似たような項目に「no-cache」がありますが、これはキャッシュはされた上で使う際の取り決めの内容なのでキャッシュ自体はされてしまうので間違えて設定しないよう注意が必要になります。(no-cacheはオリジンへ「自分が保持しているキャッシュは最新のキャッシュかどうか」問い合わせて問題ないかチェックし問題なければ使うみたいな挙動になります。)
ちなみに、上記の性質上、「no-cache」は「max-age」との共存はできません。
max-age=0はどうか?
これでもキャッシュされなさそうな設定な気がします。ただ、これも確実ではないです。もし他の項目が解釈されなかった場合にこれが無視されて普通にキャッシュされてしまうためです。なのであえて指定する必要もないです。
HTMLのmetaタグで制御する方法
注意点
- プロキシ上のキャッシュを使ってしまう場合がある。
- HTML4とHTML5で微妙に仕様が異なる。
IE11の問題点
IE11には「ノーキャッシュ」にしていてもある条件下だけはキャッシュが使われてしまう問題があります。HTTPSにすれば大丈夫なので必ず対応しましょう。
ヘッダの操作をどこで行うか?
HTTPヘッダの操作はWebサーバー、Proxyサーバー、CDNサーバーそれぞれで行うことができます。どこで行うかはそのアプリケーションの設計によっても違います。
Apache
mod_headersで行えます。Cache-Controlなどキャッシュ設定の変更も普通にできます。
プログラミング言語
PHPのheader関数など
ディレクトリの.htaccess
出入り口(ゲートウェイ)
ここにヘッダ設定を集約させるのが望ましいです。理由としてはどんなサイトでも変わらないためです。ゲートウェイとは具体的には、Proxyサーバーのことです。もし、Proxyがない場合はオリジンのWebサーバーなどが良いです。
以下どのようなホスティングであってもゲートウェイは存在します。
- EC2+EIP
- ELB+EC2
- S3
- AWS以外のレンタルサーバー
- VPS
もし、中で問題ある設定がされていてたとしても、ゲートウェイでヘッダーを綺麗にしてしまえば問題ないです。
ゲートウェイのデメリット
特定のパスを一律設定するのは得意だが、URLごとに個別に設定するというのは難しい。
もし、proxyなど経路上で操作を行わせたくない場合
オリジンサーバーなどでHTML/CSS/JS/画像の変更を行わせたくない場合は「no-transform」オプションを指定すればいけます。(根本的にはHTTPSで対策すれば良いが。)
もし指定しないと以下のような問題が起きる可能性があります。
- サイトのデザイン崩れ
- アセットのハッシュ不整合によるダウンロード失敗
この記事へのコメントはありません。