CloudFrontの動作をLambda@Edgeでカスタマイズする

# Lambda@Edgeとは
### 概要
CloudFrontのBehaviorに設定することのできるLambda functionで、CloudFrontの動作をカスタマイズすることのできる仕組みです。

![lambda_at_edge_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/94ce459f-04d5-94b4-7149-7eb131e74b85.png)


- クライアントからリクエストを受信したとき(Viewer request)
- オリジンサーバへリクエストする前(Origin request)
- オリジンサーバからレスポンスを受信したとき(Origin response)
- クライアントへレスポンスを送信する前(Viewer response)
 
以上4つのイベントの発生時に実行することができます。

### Lambda@Edgeの制限
通常のLambda functionとは異なる次のような制限があります。

- 実行できるのはNorth Virginia(us-east-1)リージョンのFunctionのみ
- 実行できるのは番号付きバージョンのみ(${LATEST}やエイリアスは不可)
- 使用可能なランタイムはNode.jsのみ

# クライアントに応じてレスポンス内容を変えるFunctionの作成

以前、<a href="https://qiita.com/oh-sky/items/1abec95e8388da97c6ba" target="_blank">S3にアップロードされたJPEG画像をWebPに変換する機能</a>を作成しました。
クライアントから送信されるリクエストヘッダ「Accept」の値に応じてJPEG画像とWebP画像を返し分けるFunctionを作成します。

![lambda_at_edge_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/68c5e105-2a48-1630-1c45-f6e9a1e0e5b9.png)

クライアントからのリクエスト内容に応じてOriginサーバへのリクエスト内容を変更したいため、「Origin request」をトリガーにします。

### 実装
#### Lambda function作成画面を開く　
<img width="1279" alt="Screen Shot 0001-05-24 at 14.05.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/23a3ae25-2642-438d-e859-5989ec01fddb.png">
AWS Management ConsoleでLambdaの画面を開き、右上のリージョンで「N.Virginia」を選択し「Create function」ボタンを押下します。
#### Lambda functionの作成
![Screen Shot 0001-05-24 at 14.16.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/16f0603e-b48d-d7b5-10d8-19b200613ade.png)
Runtimeは必ずNode.jsを選択します。
Execution roleは「AWSLambdaEdgeExecutionRole」テンプレートをコピーして作成するのが簡単です。
#### コードの記述　

```javascript
exports.handler = async (event, context) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    if (
        headers['accept'] //Acceptヘッダがあり
        && headers['accept'][0].value.match(/image\/webp/i)　//Acceptヘッダに image/webp が設定されていて
        && request.uri.match(/path\/to\/image\/.+\.jpg$/)　//リクエストURIが /path/to/image/〜.jpg の場合
    ) {
　　　　　// リクエストURIの末尾に .webp を付加する
        request.uri = request.uri + '.webp';        
    }

    return request;
};

```

リクエストヘッダ「Accept」の値に応じてオリジンへのリクエストURIを変更するコードをこのように作成しました。
eventオブジェクトの構造はAWSの公式ドキュメントに詳しい説明があります。
<a href="https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-content-based-routing" target="_blank">参考: Lambda@Edge イベント構造</a>

#### CloudFrontへの登録
<img width="690" alt="Screen Shot 0001-05-24 at 14.51.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/fb48753d-736f-1a7e-3471-4923909613c1.png">
functionの番号付きバージョンを作成するため、画面上部にあるActionsプルダウンメニューから「Publish new version」を押下します。
<img width="1209" alt="Screen Shot 0001-05-24 at 15.39.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/a3747014-281f-1e27-e670-e5ab83533e70.png">
新しく作成されたバージョンのConfiguration画面で、trigger候補の一覧から「CloudFront」を選択します。
<img width="1197" alt="Screen Shot 0001-05-24 at 15.42.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/5643f746-63eb-ded7-3c8e-50356e44ac2f.png">
triggerの設定フォームが表示されるので、設定するCloudFrontのディストリビューション・ビヘイビア・イベントを選択し、「Add」ボタンを押下します。
以上で設定完了です。
#### 動作確認
![Screen Shot 0001-05-24 at 16.07.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13038/3bcbd3f1-849d-8594-3279-a33cb0117ae6.png)
リクエストヘッダ `Accept: image/webp` の有無でレスポンスされる画像のContent-Typeやファイルサイズが変わることを確認します。