CloudFront+S3で公開HPの更新時エラーをLambdaを使って回避する
はじめに
この問題の根本となる原因はCloudFrontの設定にあります。
ドメインの一番最初にアクセスしたい場所を、Default Root Objectを「index.html」として指定しています。
ブラウザから指定したドメインにアクセスするとこのような形になります。
https:kokota.com
↓ DNSのドメイン解決
https:xxxxx.cloudfront.net/
↓ CloudFrontのデフォルトルートオブジェクト
https:xxxxx.cloudfront.net/index.html
このとき、ルートオブジェクトのリンクであればindex.htmlを取得できるのですが、
https:kokota.com/blog
↓ DNSのドメイン解決
https:xxxxx.cloudfront.net/blog
↓ CloudFrontのオブジェクト取得ができない
https:xxxxx.cloudfront.net/blog
というようになりhtmlファイルが取得できないため403エラーを返すようです。
解決方法
Lambda@EdgeかCloudFront Functionを使えばよいです。
CloudFrontへのリクエストをS3バケットに要求する前に、URLを書き換えてサブディレクトリに対してもindex.htmlを付与するのです。 どちらでもいいのですが、使用料金が安いCloudFront Functionを使いましょう。 機能制限はありますが今回の用途であれば十分です。
CloudFunctionの作成
CloudFrontのコンソール画面をひらき、左にあるメニューから関数を選び、新規作成します。
関数名は何でもよいのでこのように書きました。 やっていることは.htmlを末尾に付与するような関数です。
function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!uri.endsWith('.html')) {
request.uri += '.html';
}
return request;
}
これでとりあえず動くはずです。 細かい条件があれば追加してください。
画像リンクの修正
画像などをリンクしている場合、拡張子の後ろにhtts://XXXX/XXX/xxx.webp.html というようなアドレスに変換されてしまいます。 こんなアドレスは存在しないため当然、Not Foundに行き着きます。 回避するために主な拡張子のときは.htmlをつけないようにしました。これで解決するはずです。
function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}else if (!hasFileExtension(uri)) {
request.uri += '.html'; // Append .html if the URI does not have an extension
}
return request;
}
function hasFileExtension(uri) {
// List of common file extensions to check
var fileExtensions = ['.html', '.webp', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.mov','css','js'];
// Check if the URI ends with any of the file extensions
for (var i = 0; i < fileExtensions.length; i++) {
if (uri.toLowerCase().endsWith(fileExtensions[i])) {
return true;
}
}
return false;
}
CloudFront のイベントトリガー設定
AWS マネジメントコンソールで CloudFront サービスにアクセスします。 cloudFrontの該当するディストリビューションを選択してビヘイビアタブを開きます。
ビヘイビアを編集を開き、先ほど作成した関数をこのように追加します。
こんな感じ。
まとめ
cloudFrontでRoot以外のアドレスのときに更新したらエラーになっていた問題はこれにて解決です。 Google Adsenceを追加したり、エスパーニャとか行ったときの記事を追加したりいくつかやりたいことはあるのですがひとまずは形になったかと。
気長にやっていこう。