静的ウェブサイトホスティングにおけるURL正規化のリダイレクトの実施
はじめに
西藤です。
高可用性のある静的なウェブサイトホスティングを実現したい時には、Amazon S3とCloudFrontの組み合わせで構築できます。
ただし、そのような構成を取ったときにはたとえばApacheサーバーで構築した時のような .htaccess
を使ったリダイレクト設定を行うことができません。
また、Amazon S3の静的ウェブサイトホスティングの機能の「リダイレクトルール」もありますが、正規表現によるルール設定をカバーしておらず、設定するルール数が膨れてしまいがちです。
たとえば、
example.com/test/index.html
はexample.com/test/
example.com/test2/index.html
はexample.com/test2/
のように "index.html" の有り、なしを揃えた正規化を行いたい場合は
- /test/ にあるindex.htmlのURLをindex.htmlなしに
- /test2/ にあるindex.htmlのURLをindex.htmlなしに
のような形で設定を追加していく必要が出てきます。
しかし、ウェブサイトのSEOを考える上ではリダイレクトルールは正規表現を使いながらなるべく
シンプルに実現したいものです。
そこで今回はLambda@edgeを使った形で、
- 「末尾の "index.html" がない形でURL正規化」
というシナリオで検証したいと思います。
構成
S3 + CloudFrontでのウェブホスティングやその際にLambda@Edgeを使った場合の作り方の例などついては弊社ブログの
- S3静的ウェブホスティング+CloudFront+Lambda@EdgeでBasic認証をかける
- Lambda@Edgeでアクセス元の国を判別してリダイレクト | MMMブログ
- S3 + CloudFrontの静的サイト内の所定のパスにおいてBasic認証を導入する
- サイトリニューアル時のURLリダイレクトをLambda@Edgeで実現する
などにもございますので、割愛します。
これらの記事もぜひご覧ください。
Lambdaの内容
Lambda@Edgeの構築方法は省きましたので、早速コード例としましては以下の通り。
'use strict';
exports.handler = (event, context, callback) => {
console.log("=====Redirection to the URL without index.html =====");
// Get request and request headers
const request = event.Records[0].cf.request;
const headers = request.headers;
// If URL ends with index.html, redirect to URL without index.html.
const isIndex = request.uri.endsWith('/index.html');
if (isIndex) {
console.log("=====Because the URL ends with index.html , redirect to the URL without index.html =====");
const withoutIndex = request.uri.replace(//index.html$/, '/');
const response = {
status: '301',
statusDescription: 'Moved Permanently',
headers: {
location: [{
key: 'Location',
value: withoutIndex
}]
},
};
callback(null, response);
console.log("=====Redirection to the URL without index.html has ended =====");
}
// Continue request processing if requested URL doesn't end with index.html
callback(null, request);
};
具体的な流れとしては
- リクエスト時のURLの末尾が
/index.html
であるかを確認 - (それに合致した場合は)末尾の
/index.html
を/
に置き換えた形のLocation
の値を持ったレスポンスヘッダーを生成して返す - (合致していなかった場合は)リクエスト時のURLでそのままレスポンスを返す
という形になっています。
これを
というように view-request
を起点にこのLambda関数が動作するようにすることで、URL正規化のリダイレクトを実現します。
(・・・蛇足ですが、初めは "index.html" を ""(空白)に置き換えようとして、うまくリダイレクトが効いてくれず、つまづいていました。
""(空白)にしてしまうと、レスポンスヘッダーのLocation
の値がないことになってしまうことでうまく行かなかったようです。)
以上がURL正規化の準備です。次にS3上に構築したサイトの内容とアクセスした際の動作を見ていきます。
S3のウェブサイトの内容
構築したサイトの内容はこのような形です。
- サイト直下にindex.html
a
というディレクトリにindex.htmlb
というディレクトリにindex.htmlb
というディレクトリの中にあるc
というディレクトリにindex.html
という具合です。
リダイレクトが効いていない場合
では、まずサンプルとして、
- サイト直下のindex.html
- bというディレクトリ内のcというディレクトリ内のindex.html
にリダイレクトが効いていない状態でアクセスします。
サイト直下のindex.html(リダイレクト無し)
index.htmlがある場合、ない場合どちらとも同じページが表示されています。
bというディレクトリ内のcというディレクトリ内のindex.html(リダイレクト無し)
こちらもindex.html有り無しどちらも表示されました。
リダイレクトが効いた場合
では、適用前の状況がわかったことで各パターンを試します。
見え方は変わらないので、結果だけを・・・。
サイト直下のindex.html
→ index.html無しの形でサイトドメイン名直下にリダイレクト
a
というディレクトリのindex.html
→ index.html無しの形で a
というディレクトリのパスにリダイレクト
b
というディレクトリのindex.html
→ index.html無しの形で b
というディレクトリのパスにリダイレクト
b
というディレクトリの中にあるc
というディレクトリにindex.html
→ index.html無しの形で c
のディレクトリのパスにリダイレクト
どの階層においても希望通りリダイレクトが効いていました。
まとめ
以上のように、S3の「リダイレクトルール」の設定を各階層ごとに足し合わせて行かなくても、index.html有り無しのURL正規化が実現できました。
今回のようなindex.html有り無しのURL正規化のシナリオに限らず、さまざまなパターンのリダイレクトを実装する際の参考になれば幸いです。