CloudFrontでモバイルデバイスのOS判別ができるCloudFront-Is-Android-Viewer/CloudFront-Is-IOS-Viewerヘッダを確認してみた
はじめに
清水です。AWSのCDNサービスであるAmazon CloudFrontでは以前からユーザがコンテンツ表示に使用しているデバイスを判定するCloudFront-Is-Mobile-Viewer
ヘッダなどが利用可能でした。この機能自体は2014年6月のアップデートで追加されたものです。
当時はCloudFront-Is-Mobile-Viewer
、CloudFront-Is-Tablet-Viewer
、CloudFront-Is-Desktop-Viewer
の3つのみでしたが2018年11月の段階でCloudFront-Is-SmartTV-Viewer
が追加されていました。(追加された具体的なタイミングは不明です。)
これらはリクエスト時のUser-Agent
ヘッダの値に基づいてCloudFront側でそれぞれtrue
/false
に設定されます。オリジン側でこの値を参照することでモバイル用/PC用のコンテンツを出し分けたり、CloudFront側で個別のキャッシュとして扱うということが可能でした。(モバイル/PCの出し分けはオリジン側でUser-Agent
ヘッダを使用しても実現できますが、CloudFrontでキャッシュさせる場合にはUser-Agent
ヘッダの転送は適切ではありません。またモバイル/PC判定の処理をCloudFront側にオフロードできるというメリットもあるかと考えます。)
さて、これらCloudFront-Is-*-Viewer
ヘッダの詳細についてはCloudFront Developer Guideの上記の箇所に記載があったわけですが、先日ふとCloudFront Developer Guideを眺めていたところ別の箇所でも同様のデバイスを特定するヘッダについての記載を確認することができました。そしてなんとこちらは、CloudFront-Is-Android-Viewer
とCloudFront-Is-IOS-Viewer
という、モバイルデバイスのOSを判定するヘッダも追加されています!
「ビューワーのデバイスタイプを特定するためのヘッダー」 - CloudFront HTTP ヘッダーの追加 - Amazon CloudFront
本エントリではこのCloudFront-Is-Android-Viewer
ヘッダとCloudFront-Is-IOS-Viewer
ヘッダについて、実際に動作を確認してみたのでまとめてみます。CloudFront Distributionの設定でLegacy cache settingsを使用した場合は「forward all headers」とするとこれらモバイルOS判定のヘッダは利用できない(オリジンに転送されない)ため個別に「add header」で追加する必要があるなど癖?のようなものがあるようですので、Origin request policyの使用を前提として使うのが良いのかなと考えます。
CloudFront-Is-Android-Viewer/CloudFront-Is-IOS-Viewerヘッダはいつから利用可能になっていた?
実際に設定方法・動作確認を行う前に、このCloudFront-Is-Android-Viewer
ヘッダとCloudFront-Is-IOS-Viewer
ヘッダ、いつから利用可能になっていたか確認しておきましょう。CloudFrontのWhat's Newのページを確認してみますが、最近のアップデートでそれらしき項目はありません。
それなら、と、Developer Guideの該当ページをINTERNET ARCHIVE Wayback Machineでさかのぼってみましょう。「Adding the CloudFront HTTP headers - Amazon CloudFront」のアーカイブを確認しましたが、最も古いもので2020/10/28のアーカイブが確認できました。この段階からすでに、CloudFront-Is-Android-Viewer
/CloudFront-Is-IOS-Viewer
ヘッダが案内されていますね。
Using the CloudFront HTTP headers - Amazon CloudFront (INTERNET ARCHIVE Wayback Machine)
後述しますが、このモバイルデバイスのOSを判定するCloudFront-Is-Android-Viewer
/CloudFront-Is-IOS-Viewer
ヘッダは「Legacy cache settings」の「forward all headers」とした場合には利用できません。(個別に「add header」すると利用できますが。)またDeveloper Guideの記載箇所としては「ポリシーの使用」の章の「CloudFront HTTP ヘッダーの追加」になっています。(Legacy cache settingsの設定項目に該当するDeveloper Guideの記載箇所「デバイスタイプに基づいてキャッシュを設定する」 には、デバイス判別のヘッダのみの解説でこのモバイルデバイスOSの判別用ヘッダの記載はありません。)このポリシーの使用(Origin request policyとCache policy)についての機能アップデートがあったのが2020年7月末のことです。
また同じタイミング(上記アップデートの直後)でこのOrigin request policyで利用できる詳細なジオロケーションヘッダも追加されていました。
これらから、CloudFront-Is-Android-Viewer
/CloudFront-Is-IOS-Viewer
ヘッダについても同じようにOrigin request policyが利用可能になったタイミングで追加されていたのかな、と推測しています。
Origin request policyでCloudFront-Is-Android-Viewer/CloudFront-Is-IOS-Viewerヘッダを使ってみる
それでは実際に、Origin request policyを使ってCloudFront-Is-Android-Viewer
/CloudFront-Is-IOS-Viewer
ヘッダの設定を行い動作を確認していきます。今回CloudFrontに設定するオリジンはEC2インスタンスとし、内部でApache HTTP ServerとPHPを動作させておきます。また以下のファイルindex.php
を配置しておきました。デフォルトルート(/
)にアクセスすれば、アクセス時のリクエストヘッダ情報が参照できる状態です。
<?php foreach (getallheaders() as $name => $value) { echo "<p>"; echo "$name: $value"; echo "</p>\n"; } ?>
Origin request policyの作成
CloudFront側の設定、まずはOrigin request policyを作成していきます。CloudFrontのマネジメントコンソール、PoliciesのページからOrigin requestタブの[Create origin request policy]ボタンで進みます。NameとDescriptionを適切に設定します。
Origin request settingsの項目ではHeadersで「All viewer headers and the following CloudFront headers」を選択しました。(All viewer headersはに似ですが、CloudFront headersを選択する必要があります。)Add headerでOrigin requestに含めるCloudFront headersを選択します。デバイス(含むOS)判定に使用可能な以下6つを選択しました。
CloudFront-Is-Mobile-Viewer
CloudFront-Is-Tablet-Viewer
CloudFront-Is-SmartTV-Viewer
CloudFront-Is-Desktop-Viewer
CloudFront-Is-IOS-Viewer
CloudFront-Is-Android-Viewer
[Create]ボタンで作成します。
Distributionの作成
続いて上記Origin request policyを使用するDistributionを作成していきます。ポイントとなる「Cache key and origin requests」の項目のみまとめます。
「Cache key and origin requests」の項目で「Cache policy and origin request policy (recommended)」を選択します。Cache policyは今回は検証目的ということで「CachingDisabled」を選択しました。キャッシュを有効とする場合には、キャッシュキーに今回確認するCloudFront-Is-*-Viewer
のヘッダを適切に含めるようにしましょう。Origin request policyで先ほど作成した、CloudFront-Is-*-Viewer
をCloudFront headersに含めたもの指定します。(ここでは「Custom-DeviceDetectionHeaders」。)
CloudFront-Is-Android-Viewer/CloudFront-Is-IOS-Vieweヘッダの値を確認してみる
CloudFront Distributionが作成できたら、このドメイン名にアクセスしてCloudFront-Is-Android-Viewer
ヘッダ、CloudFront-Is-IOS-Viewe
ヘッダの値を確認してみましょう。
まずはMac版Google Chromeブラウザでアクセスしてみます。CloudFront-Is-Android-Viewer
/CloudFront-Is-IOS-Viewe
の2つのヘッダを確認することはできますが、当然ながらどちらもfalse
となります。(もちろん、CloudFront-Is-Desktop-Viewer
がtrue
でデバイス判定自体は正しく動作していますね。)
続いてなぜか発売日に購入したiPhone 13 ProのSafariブラウザでアクセスしてみました。しっかりとCloudFront-Is-IOS-Viewe
がtrue
になっていますね。またCloudFront-Is-Mobile-Viewer
ヘッダもtrue
になっています。
さてこのCloudFront-Is-Android-Viewer
/CloudFront-Is-IOS-Viewe
ヘッダはUser-Agent
ヘッダをもとにCloudFront側で設定している、とDeveloper Guideに記載があります。Androidデバイスの準備ができなかったため、curl
コマンドでUser-Agent
ヘッダを偽装した場合の挙動を確認してみました。
まずはUser-Agent
ヘッダを指定しなかったときのcurl
コマンドの実行結果です。デスクトップ端末として判定されていることがわかります。
% curl https://d1twxxxxxxxxxx.cloudfront.net/ <p>Host: d1twxxxxxxxxxx.cloudfront.net</p> <p>User-Agent: curl/7.64.1</p> <p>X-Amz-Cf-Id: cH_OxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxLQ==</p> <p>Connection: Keep-Alive</p> <p>Via: 2.0 d8e9xxxxxxxxxxxxxxxxxxxxxxxx9592.cloudfront.net (CloudFront)</p> <p>X-Forwarded-For: 2xxx:xx:xxxx:xxx:xxxx:xxxx:xxxx:xxxe</p> <p>Accept: */*</p> <p>CloudFront-Is-Mobile-Viewer: false</p> <p>CloudFront-Is-Tablet-Viewer: false</p> <p>CloudFront-Is-SmartTV-Viewer: false</p> <p>CloudFront-Is-Desktop-Viewer: true</p> <p>CloudFront-Is-IOS-Viewer: false</p> <p>CloudFront-Is-Android-Viewer: false</p>
続いて、curl
コマンドのオプションで-H "User-Agent: Android"
をつけてみました。実際はUser-Agent
ヘッダにより詳細な情報(Androidのバージョンやブラウザ種別など)が記載されるかと思いますが、シンプルにAndroid
の文字列で以下のようにAndroid OS使用と判定されました(CloudFront-Is-Android-Viewer: true
)。またモバイル判定のCloudFront-Is-Mobile-Viewer
ヘッダもtrue
となっています。
% curl https://d1twxxxxxxxxxx.cloudfront.net/ -H "User-Agent: Android" <p>Host: d1twxxxxxxxxxx.cloudfront.net</p> <p>User-Agent: Android</p> <p>X-Amz-Cf-Id: ouDTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxOA==</p> <p>Connection: Keep-Alive</p> <p>Via: 2.0 e6b8xxxxxxxxxxxxxxxxxxxxxxxx55ee.cloudfront.net (CloudFront)</p> <p>X-Forwarded-For: 2xxx:xx:xxxx:xxx:xxxx:xxxx:xxxx:xxxe</p> <p>Accept: */*</p> <p>CloudFront-Is-Mobile-Viewer: true</p> <p>CloudFront-Is-Tablet-Viewer: false</p> <p>CloudFront-Is-SmartTV-Viewer: false</p> <p>CloudFront-Is-Desktop-Viewer: false</p> <p>CloudFront-Is-IOS-Viewer: false</p> <p>CloudFront-Is-Android-Viewer: true</p>
もう一つ、curl
コマンドのオプションで-H "User-Agent: iPad"
をつけてみました。こちらもiOS使用と判定されますね(CloudFront-Is-IOS-Viewer: true
)。 またCloudFront-Is-Mobile-Viewer
とCloudFront-Is-Tablet-Viewer
がともにtrue
となっています。(これはDeveloper Guide記載の通り、一部のタブレットデバイスに両方をtrue
にするケースですね。)
% curl https://d1twxxxxxxxxxx.cloudfront.net/ -H "User-Agent: iPad" <p>Host: d1twxxxxxxxxxx.cloudfront.net</p> <p>User-Agent: iPad</p> <p>X-Amz-Cf-Id: PSJ0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxeg==</p> <p>Connection: Keep-Alive</p> <p>Via: 2.0 1ec5xxxxxxxxxxxxxxxxxxxxxxxx7e8e.cloudfront.net (CloudFront)</p> <p>X-Forwarded-For: 2xxx:xx:xxxx:xxx:xxxx:xxxx:xxxx:xxxe</p> <p>Accept: */*</p> <p>CloudFront-Is-Mobile-Viewer: true</p> <p>CloudFront-Is-Tablet-Viewer: true</p> <p>CloudFront-Is-SmartTV-Viewer: false</p> <p>CloudFront-Is-Desktop-Viewer: false</p> <p>CloudFront-Is-IOS-Viewer: true</p> <p>CloudFront-Is-Android-Viewer: false</p>
Legacy cache settings使用の場合のCloudFront-Is-Android-Viewer/CloudFront-Is-IOS-Viewerヘッダの挙動
これらCloudFront-Is-Android-Viewer
ヘッダとCloudFront-Is-IOS-Viewer
ヘッダですが、Developer Guideの記載箇所が「ポリシーの使用」の章の「CloudFront HTTP ヘッダーの追加」であることから、Origin request policy(とCache policy)使用時にのみ使える機能であり、Legacy cache settingsでは使用できないのではないか、という予想ができます。この点も実際に確認しておきましょう。(後述しますが、この予想は正解ではありませんでした。)
Legacy cache settingsでforward all headersとした場合
オリジンとなるEC2は先ほどと同様の設定で、「Cache key and origin requests」の項目で「Legacy cache settings」を設定したCloudFront Distributionを作成していきます。「Legacy cache settings」の設定詳細では以下のように、Headersの項目で「All」を選択してすべてのヘッダをオリジンに転送するようにしました。
Distribution作成後、このCloudFrontドメイン名にアクセスしてみます。以下のように4つのデバイス判定情報のヘッダは確認できましたが、CloudFront-Is-Android-Viewer
ヘッダならびにCloudFront-Is-IOS-Viewer
ヘッダは確認できませんでした。「Legacy cache settings」で「forward all headers」とした場合はモバイルデバイスのOSを判定するヘッダは利用できないということになります。
Legacy cache settingsで転送するheaderを個別に追加する場合
続いて「Legacy cache settings」の設定、Headersで「Include the following headers」を選択し、オリジンに転送するヘッダを選択した場合の挙動です。「Add header」を選択するとオリジンに転送するヘッダを個別に選択していくことができますが、ここにCloudFront-Is-Android-Viewer
ヘッダ、CloudFront-Is-IOS-Viewer
ヘッダがあるので選択してみます。そのほか、デバイス判定の4つのヘッダも加えておきました。
Distributionを作成したら実際にアクセスしてみます。CloudFront-Is-Android-Viewer
ヘッダならびにCloudFront-Is-IOS-Viewer
ヘッダがオリジンへのリクエストに含まれていることが確認できました。「Legacy cache settings」で「Add Header」する場合には、該当のHeaderを選択することでモバイルデバイスのOS判定のヘッダも利用できるという結果になりました。
(実は、てっきりこのモバイルデバイスのOS判定用ヘッダ、CloudFront-Is-Android-Viewer
ヘッダならびにCloudFront-Is-IOS-Viewer
ヘッダはOrigin request policy使用時のみの機能でLegacy cache settingsでは使えないのでは、と思っていたのですが、「すべてのヘッダを転送」ではなく「個別に転送するヘッダを指定」するかたちであれば使用が可能でした。)
まとめ
CloudFrontのモバイルデバイスOS判定用のヘッダであるCloudFront-Is-Android-Viewer
/CloudFront-Is-IOS-Viewer
ヘッダについて、利用可能になったタイミングを探りつつつ、実際に設定してその動作を確認してみました。ドキュメント(Developer Guide)記載の箇所などからOrigin request policyで利用することが前提になっているかとは思いますが、Legacy cache settingsでもヘッダを個別に追加するかたちであれば利用が可能でした。
PC環境(Desktop-Viewer)よりもモバイル環境(Mobile-Viewer)のほうがOSを意識する場面は多いのかな、と個人的には感じています。(PC環境であればWindows/Macというよりも、ブラウザがGoogle ChromeかFirefoxか、などを意識するかと思います。対して、モバイル環境であれば逆にブラウザよりもOS(iOSかAndroidか)を意識するのかなと思います。)そのためこのCloudFrontのCloudFront-Is-Android-Viewer
ヘッダ/CloudFront-Is-IOS-Viewer
ヘッダは便利に活用できるのかな、と考えています。冒頭でも述べましたが、キャッシュヒット率などを考慮するとUser-Agentヘッダをキャッシュキーとして利用するのは適切ではありません。モバイルデバイスのOS判定もCloudFront側に任せてしまいましょう。