はじめに
CloudFrontからオリジンへのリクエスト時に特定のHTTPヘッダーを含めるには、オリジンリクエストポリシーの設定が必要です。
CloudFrontを使用すると一部HTTPヘッダーが書き換えられ、特にUser-AgentヘッダーはAmazon CloudFront
になってしまい、オリジンサーバーでUser-Agentを利用してデバイスの判定ができなくなります。
ただし、オリジンリクエストポリシーでCloudFront-Is-Mobile-Viewer
といったヘッダーをオリジンリクエストに追加することで、オリジンサーバーでCloudFront-Is-Mobile-Viewer
ヘッダーの値を使ってデバイスの判定ができるようになります。
@nuxtjs/device
といったライブラリでは、このヘッダーに応じてデバイスの判定をすることができ、CloudFrontを導入してUser-AgentがAmazon CloudFront
になってしまっても、そのままレスポンシブ対応をすることができます。
そんな便利なオリジンリクエストポリシーのヘッダー追加機能ですが、CloudFront + API Gatewayの構成の構築をしていて、CloudFront-Is-Mobile-Viewer
といったヘッダーの値が意図したものにならないことがありました。
ヘッダーの値が意図したものにならなかった時の状況
- ビヘイビアでオリジンをLambda関数にルーティングするAPI Gatewayに設定する。
- 上記ビヘイビアのオリジンリクエストポリシーで
CloudFront-Is-Mobile-Viewer
を追加する。 - API GatewayからルーティングされるLambda関数はSSRでHTMLを配信している。(モバイルかデスクトップかで表示を分けたい)
- モバイルでアクセスしても、Lambda関数でAPI Gatewayからのリクエストヘッダーを見ると、
CloudFront-Is-Mobile-Viewer
がfalse
になっている。 - また、オリジンリクエストポリシーで設定した覚えのないヘッダーがなぜか追加されている。
'cloudfront-forwarded-proto': 'https', 'cloudfront-is-desktop-viewer': 'true', 'cloudfront-is-mobile-viewer': 'false', 'cloudfront-is-smarttv-viewer': 'false', 'cloudfront-is-tablet-viewer': 'false', 'cloudfront-viewer-country': 'JP',
構成図
問題の原因
API GatewayのEndpoint Typeをエッジ最適化(Edge)にしていたため。
Endpoint Typeをリージョン(Regional)にすることで、モバイルからアクセスしたときにCloudFront-Is-Mobile-Viewer
の値はtrue
になり、設定した覚えのないヘッダーが送信されることもなくなりました。
API Gatewayのドキュメントによると、エッジ最適化 API エンドポイントの場合、こちらが設定したCloudFront ディストリビューションとは別にCloudFront ディストリビューションを経由することになるため、そちらのヘッダーが適用されることになってしまったのではないかと考えられます。
リージョン API エンドポイントではCloudFront ディストリビューションを経由せず、リージョン固有の API Gateway API を直接ターゲットとするため、こちらが設定したCloudFront ディストリビューションのヘッダーが適用されて、意図したヘッダーをLambda関数で取得することができたと考えられます。
CloudFrontを導入する意図がクライアントへの接続時間の改善であれば、CloudFront + API Gateway(リージョンAPIエンドポイント)の構成ではなく、API Gateway(エッジ最適化 API エンドポイント)で十分かもしれません。
CloudFrontからAPI Gatewayへのオリジンリクエストでヘッダーを追加する場合、エッジ最適化 API エンドポイントで設定していると、ヘッダーの値が意図しない値になったり、意図しないヘッダーが追加されている可能性があるのでご注意ください。