TL;DR
先読みリクエスト(プリフェッチ, Prefetch)はcssだけじゃなくて他のURLにも飛ぶケースがある。
特定のエンドポイントに対して、
- ユーザーのアクションに起因するGETリクエストの件数をより正確に知りたい
- 割と重い処理なので余計なリクエストはなるべく処理したくない
上記ニーズがある場合プリフェッチ対策をした方が良い。
経緯
あるWebシステムを開発中、テストサーバーに対してどう考えても意図しないGETリクエストがログに入ってきたため、原因について考えた。
調べたところ、ブラウザバーに何かを入力したりした時にブラウザが先読み(プリフェッチ)処理としてGETリクエストを飛ばすことがあるらしく、そのリクエストに関してはヘッダーに固有の値が設定されるため、それぞれのブラウザの仕様に対して検知処理を実装して対応した。
各ブラウザごとのプリフェッチを示すヘッダー
Chrome(Chromium)
Purpose: prefetch
または X-Purpose:prefetch
https://www.chromestatus.com/feature/6247959677108224
https://bugs.chromium.org/p/chromium/issues/detail?id=86175#c65
Firefox
X-Moz: prefetch
https://developer.mozilla.org/ja/docs/Web/HTTP/Link_prefetching_FAQ
Safari
X-Purpose: preview
※ 使ってないという情報もあり
クローラーやネイティブアプリからのプリフェッチに関して
アトリビューション分析にBotやクローラー対策を行うのはもちろんのことですが、その他にもSNSの広告フィードに対して掲載されたページが事前にBotがキャッシュする場合に、プリフェッチ機能が使われるようです。(thank you @fujitatakesh )
プリフェッチのしくみとFacebookでの利用方法を理解する | Facebook Businessヘルプセンター
広告がクリックされると、最初のページはFacebookのキャッシュから読み込まれます。
この場合を考えると、プリフェッチされたくないURLをSNS上での操作で制御できるケースもありますが、Facebook以外でも同様の仕様が取られている場合に、広告のアトリビューション分析をサーバーサイドのHTMLへのGETリクエストを基に計測するのでは不十分なケースがあると考えられるので、javascriptなり何なりでユーザーの起点で計測できるように考慮された設計になっている方が良いと思います。
実装例
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
public static boolean isPrefetchRequest(HttpServletRequest request) {
return StringUtils.equalsAny(request.getHeader("purpose"), "Prefetch", "prefetch") ||
StringUtils.equalsAny(request.getHeader("X-moz"), "Prefetch", "prefetch") ||
StringUtils.equalsAny(request.getHeader("X-Purpose"), "Preview", "preview") ||
StringUtils.equalsAny(request.getHeader("X-Purpose"), "Prefetch", "prefetch");
}
※ Javaの場合ヘッダーのキーを case insensitive
に評価することと、値は小文字で来ているらしいけど保険を取る目的で大文字小文字を含めて評価しているため上記のような実装になっている→Link prefetching FAQ - HTTP | MDN
補足
- 軽く調べた感じではブラウザごとにフワフワしてる仕様なので、変更が入る前提で経過観察する。
もちろん、このリクエストヘッダーはまったく標準化されておらず、将来のMozillaリリースで変更される可能性があります。
Chromeは「X-Purpose:prefetch」または「Purpose:prefetch」ヘッダーを使用します。
-
もちろんプリフェッチしたデータが実際にユーザーに表示される可能性もあるので、
プリフェッチなら200の空ページを返す
みたいな雑な実装は思わぬ副作用となる可能性に注意した方が良い。- コンバージョン計測に使うロジックを抜くだけとか、複雑な処理で困ってる時はリロードして下さいって表示するViewを返すようにする(ひどい)とか。
-
ユーザーのプリフェッチによるアクセス負荷の問題は2020/6/11付で慶應義塾大学メディアセンターが以下のようなリリースを出しています。
- 【注意】ブラウザの先読み機能による大量アクセスについて - 電子ジャーナル・電子ブックを使う - Keio University LibGuides at Keio University Media Center / 慶應義塾大学メディアセンター
- この事例に関しては現在、ユーザーに対して「ブラウザのプリフェッチ機能を無効にする」案内を出している状態のようですが、何か進展があればプリフェッチ対策のヒントになるかもしれません。