アレについて記す

AWSのCloudFront+S3でSPAするときにErrorPagesを使いたくない

Posted on December 02, 2017 at 22:05 (JST)

シングルページアプリケーションでURLを自然にみせるために、history.pushStateを使用することがよくあります。
このURLはサーバーに存在しないリソースを指し示すため、ブラウザリロードなどの操作でリクエストを送ると404 NotFoundになってしまいます。
一般的には、サーバーに404だったらSPAのベースとなるファイル(index.html)にリダイレクトさせる設定をすることでこの問題を回避します。

CloudFront+S3を用いてVue2で作成したSPAを配信する場合も、同様の問題が発生します。
ざっとみた感じでは、CloudFrontのErrorPagesに403エラーハンドリングを設定し、index.htmlへリダイレクトさせる方法がブログなどで多く紹介されています。
上記の方法ではAPIも同じCloudFrontを通してアクセスさせた場合に、そのAPIの結果も同様にハンドリングされてしまう問題が生じます。

本記事ではErrorPagesを利用せずにindex.htmlへリダイレクトさせる方法を紹介します。

結論

リダイレクトをErrorPagesの設定ではなく、S3でおこなう

1. Cloudフロントの設定

Behavioursに下記の設定を行う

Precedence Path Pattern 設定(備考)
0 /static/* ビルドしたJSやCSSなどを格納するS3をOriginに指定する
1 /index.html SPAのベースとなるindex.htmlを格納するS3をOriginに指定する
static/* と同じOriginで大丈夫
2 Default (*) リダイレクト用にWeb Hosting設定をしたS3をOriginに指定する

※ CloudFrontのDefault Root Objectにはindex.htmlを指定
※ リダイレクト用S3に対するOrigin Domain NameはS3コンソールのStatic website hostingに記載されているエンドポイントを入力すること。クリック時にサジェストされるのは”REST APIエンドポイント”であり、これを選んでも狙った動作はしない。

2. リダイレクト用のS3設定

バケット名

自由に命名できる。Route53から呼び出すときのように、ドメイン名と一致させなければならないといった制約はない。

アクセス権限(バケットポリシー)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your.bucket.name/*"
        }
    ]
}

パブリック(制限なし)にしておかないと、WebsiteHostingがうまく動かない。
バケットポリシーエディターにてアクセス制限設定を記載してもエラーにはならないが、実際は動かなくなる罠。

Static website hosting

リダイレクトルール入力欄に下記を記入する。

<RoutingRules>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>changeme.example.com</HostName>
      <ReplaceKeyWith>index.html</ReplaceKeyWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

上記は”このバケット内に該当のファイルが見つからない(404)場合、changeme.example.com/index.htmlへリダイレクトさせる”というルールとなる。

インデックスドキュメント・エラードキュメント入力欄には、このバケットに存在しないファイル名(例: dummy.html)を入力しておけば良い。

3. 静的ファイル用のS3設定

このバケットはCloudFrontからのアクセスのみ許可したかった(※)ので、バケットホスティングは無効にした。

※ 開発中の画面へのアクセスを禁止するための常套手段。WAFによるIP制限やLambda EdgeによるBasic認証をCloudFrontに仕掛けるのと組み合わせることでアクセス制限をかけることができる。

おわりに

今回の記事のまとめ

  • S3のリダイレクト機能を使えば、CloudFrontのErrorPagesを使わずに済む
  • S3のリダイレクト機能を使うには、S3のWebsite Hostingを有効にする必要がある
  • S3のバケットポリシーがパブリックになっていないと、Website Hostingは動作しない
  • S3のWebsite Hostingを有効にしていても、CloudFrontにてエンドポイント指定を間違えると動作しない

CloudFrontとS3の連携をおこなうには、S3のWebsite Hosting機能で出来ること、出来ないことを把握することが重要!

おまけ

Amazon ウェブサイトと REST API エンドポイントの主な違い
http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/WebsiteEndpoints.html