スマートキャンプのエンジニア入山です。
皆さんは、AWS Lambdaを知っていますか?知らない方でもサーバーレスという単語は聞いたことがあるのではないでしょうか。
Lambdaはいままでプログラムを実行する上で必要不可欠だったサーバを用意(構築・運用)しなくても、実行したいプログラムをLambda関数として作成・登録するだけで、プログラムを動作させることが可能なサーバーレスコンピューティングサービスです。
2014年にサービスが公開されてから着実にアップデートを重ねており、現在では柔軟かつ幅広い用途で利用することができます。
LambdaにはCloudFrontと連携して動作させることのできる Lambda@Edge という機能があり、今回はCloudFront+S3でのSPA構成の際にLambda@Edge(CloudFrontのエッジサーバーで利用できるLambda)を活用した例を紹介しようと思います!
AWS Lambda@Edgeとは
Lambda@Edgeとは、CloudFrontのBehaviorに設定可能なLambda Functionのことです。
Lambda FunctionをCloudFrontのエッジサーバにデプロイしておくことで、CloudFrontへのアクセス/レスポンスをインターセプトしてLambda関数を実行し、 レスポンス自体を変えたり、二次処理を実行するなど、CloudFrontの動作をカスタマイズすることが出来ます。
処理を差し込む事が可能なのは、以下の4箇所となります。
(公式HPから引用 : CloudFront Lambda@Edge での AWS Lambda の使用 - AWS Lambda)
- Viewer Request: CloudFront がビューワーからリクエストを受信した後
- Origin Request: CloudFront がリクエストをオリジンサーバーに転送する前
- Origin Response: CloudFront がオリジンからレスポンスを受信した後
- Viewer Response: CloudFront がビューワーにレスポンスを転送する前
活用例1
やりたいこと:オリジンへのリクエストをリダイレクトしたい
Web運用においてリクエストをリダイレクトしたい場面は、少なくないと思います。
SPAでHistoryAPIを利用する場合では、URIに対応したHTMLファイルが存在しないため、ブラウザリロード時などのリクエストがエラーになってしまいます。一般的には、403/404などのエラーページをindex.htmlにリダイレクトすることでこの問題を回避すると思います。
実現方法:Origin RequestでURIを変更する
Origin RequestにLambda関数を設定することで、柔軟にURIを書き換え、リクエストをリダイレクトさせることが出来ます。
以下は、index.htmlへリダイレクトするLambda関数の例です。
exports.handler = (event, context, callback) => { const {request} = event.Records[0].cf; const currentUri = request.uri; // URIにドットを含む場合は、アセットへのアクセスとみなしてリライトしない if (currentUri.indexOf('.') !== -1) { console.log(`Don't rewrite. Uri is ${currentUri}`); return callback(null, request); } const newUri = '/index.html'; console.log(`Old URI: ${currentUri}`); console.log(`New URI: ${newUri}`); request.uri = newUri; return callback(null, request); };
活用例2
やりたいこと:レスポンスヘッダをカスタマイズしたい
Webページを公開するときのセキュリティ対策などで、レスポンスヘッダをカスタマイズしたいという要望もよくあると思います。
通常であればNginxやApacheといったWebサーバーの設定で対策するのが一般的ですが、SPA(CloudFront+S3)の場合はレスポンスヘッダはカスタマイズし辛いと思います。
実現方法:Viewer Responseでレスポンスヘッダを変更する
Viewer ResponseにLambda関数を設定することで、ユーザーへレスポンスを返す直前でレスポンスヘッダを編集することが出来ます。
以下は、X-FRAME-OPTIONSを付与し、クリックジャッキング対策をする関数の例です。
'use strict'; exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; /* X-Frame-Options: DENY Content-Security-Policy: frame-ancestors 'none' */ headers['content-security-policy'] = [{ key: 'Content-Security-Policy', value: "frame-ancestors 'none'" }]; headers['x-frame-options'] = [{ key: 'X-Frame-Options', value: 'DENY' }]; callback(null, response); };
まとめ
今回は、Lambda@Edgeを活用してSPAの動作をカスタマイズする例を紹介しました。 Lambda@Edgeを利用することで、CloudFrontでの配信コンテンツに対して柔軟に処理を行うことができるようになるため、SPAにおけるクライアント運用の利便性を向上させることが出来ます。少しでも皆さんの参考になれば幸いです!