ブログに戻る

フォロー&ご登録

英語のみで利用可能

このページは現在英語でのみ閲覧可能です。ご不便をおかけして申し訳ございませんが、しばらくしてからこのページに戻ってください。

ETag の詳細と使用方法

Leon Brocard

Principal Solutions Architect, Fastly

ETag (Entity Tag) は HTTP の非常に便利なパーツのひとつであり、これを活用することでリソースの効率的なキャッシュを実現し、サイトの高速化につなげることができます。ETag によって同じリソースの複数のバージョンを識別することが可能になりますが、誤用や不適切に実装されることが多く、ETag の利用を通じて得られるはずのパフォーマンス上のメリットが失われてしまっているケースがよく見受けられます。ETag の実装を最適化することで、大規模なコードのリファクタリングを行うことなくサイトを高速化し、オリジンへのコールを削減できます。

私は Fastly の Solutions Engineering チーム (スタッフ募集中です!</u>) の一員として、柔軟性の高い Fastly のエッジ・コンピューティング・クラウドを使用してお客様のソリューションを構築しています。その過程で、HyperText Transfer Protocol (HTTP) の小さな一部に不可解な部分があるのを目にすることが時々あります。直近のケースでは、ETag が原因でした。そこでこのブログでは、その際に私が学んだことをご紹介します。仕様については、ETag レスポンスヘッダーフィールドのシンタックスとセマンティクスを定義している RFC 9110</u> をご覧ください。このブログ記事では ETag の詳細と最適な使用方法に加え、実際によく見られる ETag の利用と誤用の違いの見分け方を理解できます。 

ETag とは何か

ETag は、HTTP レスポンスヘッダーのフィールドのひとつで、リソースを再度ダウンロードすることなく、リソースに変更があったかどうかを簡単に確認できるようにすることで (このプロセスは「再検証」と呼ばれます)、キャッシュ動作をサポートします。この仕組みでは、リソースの特定のバージョンに対して、非常に短い形式で ETag が割り当てられます。これは通常、MD5 や SHA-1 などのハッシュ関数の結果です。

最良のタイプのキャッシュプロセスは、Cache-Control ヘッダーフィールドを使用して、ブラウザにレスポンスが明示的にキャッシュされる場合など、リクエストが発生しないケースです。これについて詳しくは、実際のネットワークでの Cache-Control の使用</u>に関するブログ記事をご覧ください。

2番目にベストなキャッシュプロセスは、リクエストが発生しても、ブラウザが最後に対象のリソースをフェッチしてからそのリソースに変更がないため、レスポンスボディが必要ないケースです。ここで ETag が役に立ちます。

ETag の実際の値は仕様で定義されておらず、サーバーに任されています。Fastly から見ると、不透明な値を保存することになりますが、それを何らかの方法で解析・解明しようとすることはありません。オリジンサーバーはリクエストされたリソースに変更があったかどうかを判断し、変更がないと判断すると、キャッシュ済みのリソースを使用できると教えてくれます。

ETag は、リソースを再検証するベストな方法とは必ずしも限りません。リソースが最後に更新されたのがいつか分かっていて、1秒の解決で十分な場合は、Last-Modified レスポンスヘッダーフィールドを代わりに使用することをお勧めします。つまりブラウザは「私が最後にこのコンテンツをフェッチした時から変更があった場合にのみ、コンテンツを送ってください」と頼めるのです。最終更新日を記録するのは、ETag を生成するよりも簡単かもしれません。

A modern CDN gives you huge improvements in caching, SEO, performance, conversions, & more.

詳細

実際の例

仕様を読むこともできますが、面倒ですよね。そこで実際の例を見ていきましょう。分かりやすくするために、いくつかのヘッダーフィールドを省略します。

以下は、Fastly のホームページをフェッチするブラウザからのリクエストの例です。

> GET / HTTP/2
> Host: www.fastly.com
...

本文を含む Fastly サーバーからのレスポンスはこちらです。

< HTTP/2 200 
< Cache-Control: max-age=0, must-revalidate
< Content-Length: 524,653
< ETag: "ebeb4dbc1362d124452335a71286c21d"
...

このレスポンスは、ページを使用する前にブラウザによってページが再検証される必要があることを意味しています。再検証するには、前のレスポンスの ETag 値を If-None-Match リクエストヘッダーに使用してリクエストを実行する必要があります。「If-None-Match」は、あまり英語としてはよくできた表現ではなく、本来なら「Only-Send-The-Body-If-The-ETag-Is-Different-From-This-One」(ETag がこれと異なる場合にのみこの本文を送信する) とでもすべきでしょうが、少々長すぎると思われます。そこで、次にエンドユーザーが Fastly のホームページにアクセスしたい場合、ブラウザは若干異なるリクエストを送信します。

> GET / HTTP/2 
> Host: www.fastly.com
> If-None-Match: "ebeb4dbc1362d124452335a71286c21d".
...

If-None-Match タグで指定された ETag と同じ ETag が引き続きホームページに使用されている場合は、未更新の意味を持つ304のステータスコードを返し、ブラウザは以前フェッチしてブラウザキャッシュに保存した本文を使用します。

< HTTP/2 304 
...

2度目のリクエストからこのプロセスのメリットが得られます。本文がネットワークを横断して送信される必要がないためです。送信されるバイト数が減ることで、Web パフォーマンスが向上します。

ETag の使用方法

Web 全体で ETag が実際にどのように使用されているか見てみましょう。HTTP Archive</u> は定期的に Web のトップサイトをクロールし、分析に利用できるさまざまな情報を記録しています。ここでは、合計10億1,984万6,153件のリソースをクロールした 2023-02-01 HTTP Archive のモーバイルクロールを取り上げます。ETag のレスポンスヘッダーフィールドは、およそ4分の1のリソースで使用されています。

以下は、使用頻度の高い上位20の ETag です (サイズは使用頻度の高さを示しています)。ほとんどが16進数の値のようです。一般的に二重引用符で囲まれていますが、W/のプリフィックスや +gzip のポストフィックスが使用されていることもあります。

一般的に、ETag は多くのWebサイトで読み込まれるオブジェクトに使用されています。これらのほとんどが、広告用プラットフォームや React 16.4.0</u>React DOM 16.14.0</u>Font Awesome 4.7.0</u> です。これらのライブラリは最新バージョンではないかもしれませんが、このクロールではこれらの ETag が最も頻繁に使用されていました。

ETag は同じリソースの異なるバージョンを識別するために使用されており、これにはいくつかの手法があります。最も単純な方法として、リソースがバージョン化されている場合にバージョン番号を ETag に使用することが挙げられます。

以下はバージョン番号を使用していると思われるタグのデータです。バージョン化されているリソースのほとんどに変更がないようですが、変更がある場合は何度も更新されているようで、「バージョン3」が使用されている ETag は非常に稀です。

フォントライブラリの特定のバージョンと一致する共通の ETag 値を、どのようにして検出できたかについて興味のある方もいらっしゃるかと思います。リソースのコンテンツのハッシュを使用してバージョンを特定することが可能です。fontawesome-webfont.woff2 というファイルのバージョン4.7.0の場合、16進数 (32文字から成る128ビット) での MD5 ハッシュ値は、af7ae505a9eed503f8b8e6982036873e になります。この MD5 を使用するメソッドは、トップ20に食い込むほど多くの Web サーバーとWebサイトで使用されています。

最も多く ETag として使用されているハッシュは何かというと、二重引用符を排除して ETag の長さに注目すると、MD5 と SHA-1 が最も一般的であることが分かります。

暗号化の目的で言えば、MD-5 と SHA-1 はセキュアではないと見なされていますが、リソースに変更があったかどうかを確認する目的においてはおそらく問題ないでしょう。

よく使用されるハッシュの長さは似ています。なぜ37桁のハッシュの使用頻度が高いかというと、+gzip のポストフィックスを持つ MD5 ハッシュが37桁だからです。これについては、また後ほど解説します。

上述のように、使用頻度の高い ETag の中に、W/ のプリフィックスを持つものがありました。ETag は検証力が高いものも低いものもありますが、デフォルトの場合に最も高い検証力を発揮します。データに変更があると、検証力の高い ETag の値も変更します。一方、W/ のプリフィックスがある場合、検証力が弱いことを示しています。データに変更があった場合、検証力の弱い ETag の場合、値が変更されない可能性があります。以下のように、ほとんどの ETag の検証力は高いです。

使用頻度が高い ETag の別の例として、"95e1b50b0c179aefb47b5b211bb347b5+gzip" があります。お察しのとおり、これらのレスポンスは gzip で圧縮されています。本文を圧縮することで同じリソースの異なるバージョンが確実に作成されるため、ETag も変わることが予想されます。

最も一般的なポストフィックスは -gzip と -br です。

リソースの Content-Type は、検証力の弱い ETag を使用する割合に影響します。圧縮化することで異なるバージョンが作成され、ポストフィックスを持つ検証力の高い ETag または検証力の弱い ETag が使用されます。 

CSS や JavaScript、SVG などの圧縮タイプでは、検証力の弱い ETag が使用される傾向があります。

"1637097310169751"もよく使用される ETag のひとつで、UNIX エポックからのマイクロ秒の数値と非常に似ているように見えます。これは 2021-11-16T21:15:10Z を意味し、リソースが最後に更新された日時であると思われます。このリソースはあまり頻繁に更新されていないようなので、私だったら Last-Modified のレスポンスヘッダーフィールドを使用するでしょう。

ETag のベストプラクティス

ETag がどのように使用されているかを確認したところで、今度は ETag の最適な活用方法について見てみましょう。 

  1. ブラウザーがリソースを再検証できるよう、リソースに Last-Modified や ETag などの検証用ヘッダーフィールドを使用します。

  2. ETag は有効でなければなりません。二重引用符で囲まれ、W/ のプリフィックスを任意で追加できます。

  3. リソースが厳密にバージョン化されている場合、バージョン番号を使用する検証力の高い ETag が必要です。

  4. リソースが厳密にバージョン化されていない場合、コンテンツのハッシュを使用する検証力の高い ETag が必要です。

  5. 同じ画像に異なる画像形式が使用されている場合や、コンテンツコーディングを使用して圧縮されている場合など、リソースの異なるバージョンにそれぞれ独自のタグを使用する必要があります。検証力の高いまたは低い ETag のどちらを使用すべきかは、リソースのバージョンによります。

ETag の誤用

Web で ETag が不適切に使用されているケースが時々見られます。ETag が適切に使用されないと、最新のコンテンツが表示される必要があるにもかかわらず、失効済みコンテンツが表示される可能性があります。

上述の上位20の ETag のうち、二重引用符のない OPTOUT は無効なタグでした。これは、単一の誤って設定されたアドサーバーでした。

このように英単語が使用されている無効な ETag が多数存在します。以下はその一例です。

ETag: $etagFile
ETag: abcdefg
ETag: custom
ETag: default
ETag: hash
ETag: himom
ETag: immutable
ETag: null
ETag: SAMEORIGIN
ETag: tag
ETag: undefined
ETag: Unkown

上記より頻度は少ないですが、テンプレートシステムのように見える有効なタグが不適切に使用されていて、正しい ETag が代わりに使用されていないケースが見られます。

ETag: "AssetsCalculatedEtagValue"
ETag: "CalculatedEtagValue"
ETag: "CalculatedEtagValue"

これらのうち、少なくともひとつはサンプルコード</u>です。本番環境にリリースする前にサンプルコードが完全な状態にあることを必ず確認する必要があります。

"3/19/2017 6:35:34 PM" のように、スペースを含む ETag を見かけることがありますが、スペースは有効ではありません。

W/W/"49-FHKkWnYgBQtmkHTlg06OHZmoo5A” のように「2重に弱い」ETag が使用されているケースもありますが、これも有効ではありません。

まとめ

このブログ記事では、ETag の詳細とベストプラクティスをご紹介しました。これでリソースバージョンの検証は完璧です!