

# Lambda@Edge を使用してエッジでカスタマイズする
<a name="lambda-at-the-edge"></a>

Lambda@Edge は AWS Lambda の拡張です。Lambda@Edge は、Amazon CloudFront が配信するコンテンツをカスタマイズする関数を実行できるコンピューティングサービスです。Node.js または Python 関数は、Lambda コンソールで 1 つの AWS リージョン、米国東部 (バージニア北部) で作成できます。

関数を作成したら、Lambda コンソールまたは CloudFront コンソールを使用してトリガーを追加し、サーバーをプロビジョニングまたは管理することなく、ビューワーに近い AWS ロケーションで関数を実行できます。オプションで、Lambda および CloudFront API オペレーションを使用して、関数とトリガーをプログラムで設定できます。

Lambda@Edge は、1 日あたり数個のリクエストから 1 秒あたり数千のリクエストまで自動的にスケーリングします。オリジンサーバーの代わりに、ビューワーの最寄りの AWS ロケーションでリクエストを処理すると、レイテンシーが大幅に軽減され、ユーザーエクスペリエンスが向上します。

**注記**  
Lambda@Edge は gRPC リクエストではサポートされていません。詳細については、「[CloudFront ディストリビューションでの gRPC の使用](distribution-using-grpc.md)」を参照してください。

**Topics**
+ [Lambda@Edge がリクエストとレスポンスで機能する仕組み](lambda-edge-event-request-response.md)
+ [Lambda@Edge の使用方法](lambda-edge-ways-to-use.md)
+ [Lambda@Edge 関数の使用を開始する (コンソール)](lambda-edge-how-it-works.md)
+ [Lambda@Edge 用の IAM アクセス許可とロールのセットアップ](lambda-edge-permissions.md)
+ [Lambda@Edge 関数を記述および作成する](lambda-edge-create-function.md)
+ [Lambda@Edge 関数のトリガーを追加する](lambda-edge-add-triggers.md)
+ [Lambda@Edge 関数をテストおよびデバッグする](lambda-edge-testing-debugging.md)
+ [Lambda@Edge 関数とレプリカを削除する](lambda-edge-delete-replicas.md)
+ [Lambda@Edge イベント構造](lambda-event-structure.md)
+ [リクエストとレスポンスを使用する](lambda-generating-http-responses.md)
+ [Lambda@Edge 関数の例](lambda-examples.md)

# Lambda@Edge がリクエストとレスポンスで機能する仕組み
<a name="lambda-edge-event-request-response"></a>

CloudFront ディストリビューションを Lambda@Edge 関数に関連付けると、CloudFront エッジロケーションでリクエストとレスポンスがインターセプトされます。Lambda 関数は、次の CloudFront イベントの発生時に実行できます。
+ CloudFront がビューワーからリクエストを受信したとき (ビューワーリクエスト)
+ CloudFront がリクエストをオリジンに転送する前 (オリジンリクエスト)
+ CloudFront がオリジンからレスポンスを受信したとき (オリジンレスポンス)
+ CloudFront がビューワーにレスポンスを返す前 (ビューワーレスポンス)

AWS WAF を使用している場合、Lambda@Edge ビューワーリクエストは AWS WAF ルールの適用後に実行されます。

詳細については、「[リクエストとレスポンスを使用する](lambda-generating-http-responses.md)」および「[Lambda@Edge イベント構造](lambda-event-structure.md)」を参照してください。

# Lambda@Edge の使用方法
<a name="lambda-edge-ways-to-use"></a>

Amazon CloudFront ディストリビューションでの Lambda@Edge 処理には多くの用途があります。以下に例を示します。
+ Lambda 関数 は Cookie を検査して URL を書き換え、A/B テスト用に異なるバージョンのサイトをユーザーに表示できます。
+ CloudFront は、デバイスに関する情報が含まれている `User-Agent` ヘッダーを確認し、ビューワーが使用しているデバイスに基づいて、異なるオブジェクトをビューワーに返すことができます。例えば、CloudFront は、デバイスの画面サイズに基づいて異なるイメージを返すことができます。同様に、`Referer` ヘッダーの値を考慮する関数を作成して、CloudFront が最も低い解像度のイメージをボットに返すこともできます。
+ または、他の条件の Cookie を確認できます。例えば、衣料品の通販ウェブサイトで、ユーザーが選択したジャケットの色を Cookie に保存する場合に、Lambda 関数でリクエストを変更して、CloudFront が選択した色のジャケットのイメージを返すようにできます。
+ Lambda 関数は、CloudFront のビューワーリクエストイベントまたはオリジンリクエストイベントの発生時に HTTP レスポンスを生成できます。
+ 関数でヘッダーまたは認可トークンを検査して、CloudFront がリクエストをオリジンに転送する前に、コンテンツへのアクセスを制御するヘッダーを挿入できます。
+ Lambda 関数は、外部リソースのネットワーク呼び出しを実行して、ユーザー認証情報を確認したり、追加のコンテンツを取得してレスポンスをカスタマイズしたりすることもできます。

詳細 (コード例を含む) については、「[Lambda@Edge 関数の例](lambda-examples.md)」を参照してください。

コンソールで Lambda@Edge を設定する方法の詳細については、「[チュートリアル: 基本的な Lambda@Edge 関数 (コンソール) を作成する](lambda-edge-how-it-works-tutorial.md)」を参照してください。

# Lambda@Edge 関数の使用を開始する (コンソール)
<a name="lambda-edge-how-it-works"></a>

Lambda@Edge では、CloudFront トリガーを使用して Lambda 関数を呼び出すことができます。CloudFront ディストリビューションを Lambda 関数に関連付けると、CloudFront エッジロケーションで[リクエストとレスポンスがインターセプト](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html)され、関数が実行されます。Lambda 関数では、セキュリティを強化したり、ビューワーに近い情報をカスタマイズしてパフォーマンスを向上させたりできます。

次のリストは、CloudFront で Lambda 関数を作成および使用する方法の基本的な概要を示しています。

**概要: CloudFront での Lambda 関数の作成と使用**

1. 米国東部 (バージニア北部) リージョンで Lambda 関数を作成します。

1. 番号付きバージョンの関数を保存して発行します。

   関数を変更する場合、米国東部 (バージニア北部) リージョンで関数の \$1LATEST バージョンを編集する必要があります。次に、CloudFront と連携するように設定する前に、新しい番号付きバージョンを発行します。

1. 関数を CloudFront ディストリビューションとキャッシュ動作に関連付けます。1 つまたは複数の CloudFront イベント (*トリガー*) を指定します。これにより、関数を実行できます。例えば、CloudFront がビューワーからリクエストを受け取ったときに関数を実行させるトリガーを作成できます。

1. トリガーを作成すると、Lambda が世界中の AWS ロケーションに関数のレプリカを作成します。

**ヒント**  
詳細については、「[関数の作成と更新](lambda-edge-create-function.md)」、「[イベント構造](lambda-event-structure.md)」、および「[CloudFront トリガーの追加](lambda-edge-add-triggers.md)」を参照してください。また、さらに多くのアイデアやコードサンプルを「[Lambda@Edge 関数の例](lambda-examples.md)」で参照できます。

ステップバイステップのチュートリアルについては、次のトピックを参照してください。

**Topics**
+ [チュートリアル: 基本的な Lambda@Edge 関数 (コンソール) を作成する](lambda-edge-how-it-works-tutorial.md)

# チュートリアル: 基本的な Lambda@Edge 関数 (コンソール) を作成する
<a name="lambda-edge-how-it-works-tutorial"></a>

このチュートリアルでは、CloudFront で実行される Node.js 関数の例を作成および設定することで、Lambda@Edge の使用を開始する方法を示します。この例では、CloudFront がファイルを取得するときに、セキュリティヘッダーがレスポンスに追加されます。(これにより、ウェブサイトのセキュリティとプライバシーが向上します)。

このチュートリアルでは、独自のウェブサイトは必要ありません。しかしながら、独自の Lambda@Edge ソリューションを作成するときは、同様のステップに従って同じオプションから選択できます。

**Topics**
+ [ステップ 1: AWS アカウント にサインアップする](#lambda-edge-how-it-works-tutorial-AWS)
+ [ステップ 2: CloudFront ディストリビューションを作成する](#lambda-edge-how-it-works-tutorial-cloudfront)
+ [ステップ 3: 関数を作成する](#lambda-edge-how-it-works-tutorial-create-function)
+ [ステップ 4: 関数を実行する CloudFront トリガーを追加する](#lambda-edge-how-it-works-tutorial-add-trigger)
+ [ステップ 5: 関数の実行を確認する](#lambda-edge-how-it-works-tutorial-verify)
+ [ステップ 6: 問題のトラブルシューティングを行う](#lambda-edge-how-it-works-tutorial-troubleshoot)
+ [ステップ 7: リソース例をクリーンアップする](#lambda-edge-how-it-works-tutorial-cleanup-resources)
+ [関連情報](#lambda-edge-how-it-works-tutorial-resources)

## ステップ 1: AWS アカウント にサインアップする
<a name="lambda-edge-how-it-works-tutorial-AWS"></a>

まだサインアップしていない場合は、AWS アカウントにサインアップします。詳細については、「[AWS アカウントへのサインアップ](setting-up-cloudfront.md#sign-up-for-aws)」を参照してください。

## ステップ 2: CloudFront ディストリビューションを作成する
<a name="lambda-edge-how-it-works-tutorial-cloudfront"></a>

Lambda@Edge 関数の例を作成する前に、コンテンツの提供元のオリジンを含む、操作対象の CloudFront 環境が必要です。

この例では、Amazon S3 バケットをディストリビューションのオリジンとして使用する CloudFront ディストリビューションを作成します。使用する環境が既にある場合、このステップは省略できます。<a name="lambda-edge-how-it-works-tutorial-cf-proc"></a>

**Amazon S3 オリジンを使用して CloudFront ディストリビューションを作成するには**

1. サンプルコンテンツ用に、イメージファイルなど 1～2 つのファイルで Amazon S3 バケットを作成します。そのためには、[コンテンツを Amazon S3 にアップロード](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/GettingStarted.html#GettingStartedUploadContent)するステップに従います。必ず、バケットのオブジェクトへのパブリック読み取りアクセス権を付与するアクセス許可を設定します。

1. CloudFront ウェブディストリビューションを作成するステップに従って、[CloudFront ディストリビューションを作成](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/GettingStarted.html#GettingStartedCreateDistribution)し、オリジンとして S3 バケットを追加します。ディストリビューションが既にある場合は、代わりにそのディストリビューションのオリジンとしてバケットを追加できます。
**ヒント**  
ディストリビューション ID をメモします。このチュートリアルで後ほど関数の CloudFront トリガーを追加する場合は、ドロップダウンリストでディストリビューションの ID (`E653W22221KDDL` など) を選択する必要があります。

## ステップ 3: 関数を作成する
<a name="lambda-edge-how-it-works-tutorial-create-function"></a>

このステップでは、Lambda コンソールでブループリントテンプレートから Lambda 関数を作成します。関数コードは、CloudFront ディストリビューションでセキュリティヘッダーを更新するコードを追加します。<a name="lambda-edge-how-it-works-tutorial-create-function-blueprint-proc"></a>

**Lambda 関数を作成するには**

1. AWS マネジメントコンソール にサインインして、AWS Lambda で [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/) コンソールを開きます。
**重要**  
**US-East-1 (バージニア北部)** AWS リージョン (**us-east-1**) にいることを確認します。Lambda@Edge 関数を作成するには、このリージョンに設定されている必要があります。

1. **[関数を作成]** を選択します。

1. [**関数の作成**] ページで、[**設計図の使用**] を選択し、各フィールドに「**cloudfront**」と入力して CloudFront の設計図をフィルタリングします。
**注記**  
CloudFront の設計図は、**US-East-1 (バージニア北部)** リージョン (**us-east-1**) でのみ使用できます。

1. 関数のテンプレートとして **[HTTP レスポンスヘッダーを変更する]** ブループリントを選択します。

1. 関数に関する次の情報を入力します。
   + **関数名** – 関数の名前を入力します。
   + **実行ロール** – 関数のアクセス許可を設定する方法を選択します。推奨される基本 Lambda@Edge アクセス許可ポリシーテンプレートを使用するには、[**AWS ポリシーテンプレートから新しいロールを作成する**] を選択します。
   + **ロール名** – ポリシーテンプレートで作成するロールの名前を入力します。
   + **ポリシーテンプレート** – 関数の基盤として CloudFront ブループリントを選択したことにより、Lambda は、ポリシーテンプレート **[基本的な Lambda@Edge アクセス許可]** を自動的に追加します。このポリシーテンプレートでは、世界中の CloudFront の場所で、Lambda 関数の実行を CloudFront に許可する実行ロールアクセス許可を追加します。詳細については、「[Lambda@Edge 用の IAM アクセス許可とロールのセットアップ](lambda-edge-permissions.md)」を参照してください。

1. ページの下部で、**[関数を作成]** を選択します。

1. 表示される **[Lambda@Edge へのデプロイ]** ペインで、**[キャンセル]** を選択します (このチュートリアルでは、関数を Lambda@Edge にデプロイする前に関数コードを変更する必要があります)。

1. ページの **[コードソース]** セクションまで下にスクロールします。

1. テンプレートコードを、オリジンが返すセキュリティヘッダーを変更する関数に置き換えます。たとえば、以下のようなコードを実行できます。

   ```
   'use strict';
   export const handler = (event, context, callback) => {
   
       //Get contents of response
       const response = event.Records[0].cf.response;
       const headers = response.headers;
   
       //Set new headers
       headers['strict-transport-security'] = [{key: 'Strict-Transport-Security', value: 'max-age= 63072000; includeSubdomains; preload'}];
       headers['content-security-policy'] = [{key: 'Content-Security-Policy', value: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'"}];
       headers['x-content-type-options'] = [{key: 'X-Content-Type-Options', value: 'nosniff'}];
       headers['x-frame-options'] = [{key: 'X-Frame-Options', value: 'DENY'}];
       headers['x-xss-protection'] = [{key: 'X-XSS-Protection', value: '1; mode=block'}];
       headers['referrer-policy'] = [{key: 'Referrer-Policy', value: 'same-origin'}];
   
       //Return modified response
       callback(null, response);
   };
   ```

1. **[ファイル]**、**[保存]** の順に選択して、更新したコードを保存します。

1. **[デプロイ]** をクリックします。

次のセクションに進み、関数を実行する CloudFront トリガーを追加します。

## ステップ 4: 関数を実行する CloudFront トリガーを追加する
<a name="lambda-edge-how-it-works-tutorial-add-trigger"></a>

これでセキュリティヘッダーを更新する Lambda 関数ができたので、CloudFront がディストリビューションのオリジンから受け取ったヘッダーをレスポンスに追加するように、関数を実行する CloudFront トリガーを設定します。<a name="lambda-edge-how-it-works-tutorial-add-trigger-proc"></a>

**関数の CloudFront トリガーを設定するには**

1. Lambda コンソールで、関数の **[関数の概要]** ページの **[トリガーを追加]** を選択します。

1. **[トリガー設定]** で、**[CloudFront]** を選択します。

1. **[Lambda@Edge へのデプロイ]** を選択します。

1. **[Lambda@Edge へのデプロイ]** ペインの **[CloudFront トリガーの設定]** で、次の情報を入力します。
   + **ディストリビューション** – 関数に関連付ける CloudFront ディストリビューション ID。ドロップダウンリストで、ディストリビューション ID を選択します。
   + **キャッシュ動作** – トリガーで使用するキャッシュ動作。この例では、値を **\$1** に設定したままにします。これは、ディストリビューションのデフォルトのキャッシュ動作を意味します。詳細については、「[すべてのディストリビューション設定リファレンス](distribution-web-values-specify.md)」トピックの「[キャッシュ動作の設定](DownloadDistValuesCacheBehavior.md)」を参照してください。
   + **CloudFront イベント** – 関数をいつ実行するか指定するトリガー。CloudFront がオリジンからレスポンスを返すたびに、セキュリティヘッダー関数を実行したいと思います。ドロップダウンリストで **[オリジンレスポンス]** を選択します。詳細については、「[Lambda@Edge 関数のトリガーを追加する](lambda-edge-add-triggers.md)」を参照してください。

1. **[Lambda@Edge へのデプロイを確認]** チェックボックスをオンにします。

1. [**デプロイ**] を選択して、トリガーを追加し、世界中の AWS の場所に関数をレプリケートします。

1. 関数がレプリケートするまで待ちます。これには通常数分かかります。

    レプリケーションが終了したかどうかを確認するには、[CloudFront コンソールに移動](https://console.aws.amazon.com/cloudfront/v4/home)し、ディストリビューションを表示します。ディストリビューションのステータスが **[デプロイ中]** から日時に変わるまで待ち、関数がレプリケートされたことを確認します。関数が機能することを確認するには、次のセクションのステップに従います。

## ステップ 5: 関数の実行を確認する
<a name="lambda-edge-how-it-works-tutorial-verify"></a>

Lambda 関数を作成し、CloudFront ディストリビューションに対してその関数を実行するトリガーが設定されたため、関数が正常に動作することを確認します。この例では、CloudFront が返す HTTP ヘッダーで、セキュリティヘッダーが追加されることを確認します。<a name="lambda-edge-how-it-works-tutorial-verify-proc"></a>

**Lambda@Edge 関数でセキュリティヘッダーが追加されることを確認するには**

1. ブラウザで、S3 バケット内のファイルの URL を入力します。たとえば、`https://d111111abcdef8.cloudfront.net/image.jpg` のような URL を使用できます。

   ファイル URL で使用する CloudFront ドメイン名の詳細については、「[CloudFront でファイルの URL 形式をカスタマイズする](LinkFormat.md)」を参照してください。

1. ブラウザのウェブデベロッパーツールバーを開きます。たとえば、Chrome のブラウザウィンドウで、コンテキスト（右クリック）メニューを開き、[**Inspect (調査)**] を選択します。

1. [**Network (ネットワーク)**] タブを選択します。

1. ページを再ロードしてイメージを表示し、左側のペインの HTTP リクエストを選択します。HTTP ヘッダーが別のペインに表示されます。

1. HTTP ヘッダーのリストを確認し、予期されるセキュリティヘッダーがリストに含まれていることを確認します。たとえば、次のスクリーンショットに示すようなヘッダーが表示されます。  
![\[予想されるセキュリティヘッダーがハイライト表示された HTTP ヘッダーのリスト。\]](http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/images/lambda-at-edge-security-headers-list.png)

セキュリティヘッダーがヘッダーのリストに含まれていれば、成功です。最初の Lambda@Edge 関数を正常に作成しました。CloudFront がエラーを返す場合や、その他の問題がある場合は、次のステップに進んで問題のトラブルシューティングを行います。

## ステップ 6: 問題のトラブルシューティングを行う
<a name="lambda-edge-how-it-works-tutorial-troubleshoot"></a>

CloudFront がエラーを返すか、予期どおりにセキュリティヘッダーを追加しない場合は、CloudWatch Logs を参照して関数の実行を調査できます。必ず、関数が実行された場所に最も近い AWS ロケーションで保存されたログを使用します。

例えば、ロンドンからファイルを表示する場合は、CloudWatch コンソールでリージョンを欧州 (ロンドン) に変更してみてください。<a name="lambda-edge-how-it-works-tutorial-cloudwatch-proc"></a>

**Lambda@Edge 関数の CloudWatch Logs を調べるには**

1. AWS マネジメントコンソール にサインインして、CloudWatch コンソール ([https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)) を開きます。

1. [**リージョン**] を、ブラウザでファイルを表示したときに表示されるロケーションに変更します。これは、関数が実行されている場所です。

1. 左側のペインで、[**ログ**] を選択して、ディストリビューションのログを表示します。

詳細については、「[Amazon CloudWatch で CloudFront メトリクスをモニタリングする](monitoring-using-cloudwatch.md)」を参照してください。

## ステップ 7: リソース例をクリーンアップする
<a name="lambda-edge-how-it-works-tutorial-cleanup-resources"></a>

このチュートリアルのためだけに Amazon S3 バケットと CloudFront ディストリビューションを作成した場合は、割り当てた AWS リソースを削除して、今後料金が発生しないようにしてください。AWS リソースを削除すると、追加したコンテンツは使用できなくなります。

**タスク** 
+ [S3 バケットの削除](#lambda-edge-how-it-works-tutorial-delete-bucket) 
+ [Lambda 関数を削除する](#lambda-edge-how-it-works-tutorial-delete-function)
+ [CloudFront ディストリビューションの削除](#lambda-edge-how-it-works-tutorial-delete-distribution)

### S3 バケットの削除
<a name="lambda-edge-how-it-works-tutorial-delete-bucket"></a>

Amazon S3 バケットを削除する前に、バケットのログ記録が無効であることを確認します。それ以外の場合、削除するバケットへのログの書き込みが AWS によって継続されます。<a name="lambda-edge-how-it-works-tutorial-delete-bucket-proc"></a>

**バケットのログ記録を無効にするには**

1. [https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/) で Amazon S3 コンソールを開きます。

1. バケットを選択し、[**プロパティ**] を選択します。

1. [**プロパティ**] から [**ログ記録**] を選択します。

1. [**有効**] チェックボックスをオフにします。

1. [**Save**] を選択します。

これで、バケットを削除できます。詳細については、*Amazon Simple Storage Service コンソールユーザーガイド*の「[バケットの削除](https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html)」を参照してください。

### Lambda 関数を削除する
<a name="lambda-edge-how-it-works-tutorial-delete-function"></a>

Lambda 関数の関連付けを削除する手順と、関数自体を削除する手順 (オプション) については、「[Lambda@Edge 関数とレプリカを削除する](lambda-edge-delete-replicas.md)」を参照してください。

### CloudFront ディストリビューションの削除
<a name="lambda-edge-how-it-works-tutorial-delete-distribution"></a>

CloudFront ディストリビューションを削除する前に、ディストリビューションを無効にする必要があります。無効になったディストリビューションは機能しなくなり、料金も発生しません。無効にしたディストリビューションはいつでも有効にすることができます。無効にしたディストリビューションを削除すると、使用できなくなります。<a name="lambda-edge-how-it-works-tutorial-delete-distribution-proc"></a>

**CloudFront ディストリビューションを無効にして削除するには**

1.  で CloudFront コンソールを開きます[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)

1. 無効にするディストリビューションを選択してから [**Disable (無効化)**] を選択します。

1. 確認を求められたら、[**Yes, Disable (はい、無効化する)**] を選択します。

1. 無効にしたディストリビューションを選択してから [**削除**] を選択します。

1. 確認を求めるメッセージが表示されたら、[**Yes, Delete (はい、削除します)**] を選択します。

## 関連情報
<a name="lambda-edge-how-it-works-tutorial-resources"></a>

Lambda@Edge 関数の動作について基本的な理解を得たので、以下を参照してさらに詳しく学習します。
+ [Lambda@Edge 関数の例](lambda-examples.md)
+ [Lambda@Edge 設計のベストプラクティス](https://aws.amazon.com/blogs/networking-and-content-delivery/lambdaedge-design-best-practices/)
+ [Lambda@Edge を使用したレイテンシーの軽減とエッジへのコンピューティングの移行](https://aws.amazon.com/blogs/networking-and-content-delivery/reducing-latency-and-shifting-compute-to-the-edge-with-lambdaedge/)

# Lambda@Edge 用の IAM アクセス許可とロールのセットアップ
<a name="lambda-edge-permissions"></a>

Lambda@Edge を設定するには、AWS Lambda に対する以下の IAM アクセス許可およびロールが必要です。
+ [IAM アクセス許可](#lambda-edge-permissions-required) – これらのアクセス許可により、Lambda 関数を作成して CloudFront ディストリビューションに関連付けることができます。
+ [Lambda 関数実行ロール](#lambda-edge-permissions-function-execution) (IAM ロール) – Lambda サービスプリンシパルは、このロールを引き受けて関数を実行します。
+ [Lambda@Edge のサービスリンクロール](#using-service-linked-roles-lambda-edge) – サービスリンクロールにより、特定の AWS のサービス が Lambda 関数を AWS リージョン にレプリケートし、CloudWatch が CloudFront ログファイルを使用できるようになります。

## Lambda@Edge 関数を CloudFront ディストリビューションに関連付けるために必要な IAM アクセス許可
<a name="lambda-edge-permissions-required"></a>

Lambda に必要な IAM アクセス許可に加え、ユーザーは、Lambda 関数を CloudFront ディストリビューションに関連付けるための以下の IAM アクセス許可が必要です。
+ `lambda:GetFunction` – Lambda 関数の設定情報を取得するためのアクセス許可、およびその関数を含む `.zip` ファイルをダウンロードするための署名付き URL を取得するアクセス許可を付与します。
+ `lambda:EnableReplication*` – Lambda レプリケーションサービスが関数コードと設定を取得するためのアクセス許可をリソースポリシーに付与します。
+ `lambda:DisableReplication*` – Lambda レプリケーションサービスが関数を削除するためのアクセス許可をリソースポリシーに付与します。
**重要**  
`lambda:EnableReplication*` および `lambda:DisableReplication*` アクションの最後にアスタリスク (`*`) を追加する必要があります。
+ リソースに対して、次の例のように、CloudFront イベントが発生した場合に実行する関数バージョンの ARN を指定します。

  `arn:aws:lambda:us-east-1:123456789012:function:TestFunction:2`
+ `iam:CreateServiceLinkedRole` – Lambda@Edge が CloudFront で Lambda 関数をレプリケートするために使用するサービスリンクロールを作成するアクセス許可を付与します。Lambda@Edge を初めて設定すると、サービスリンクロールが自動的に作成されます。Lambda@Edge を使用する他のディストリビューションにこのアクセス許可を追加する必要はありません。

  
+ `cloudfront:UpdateDistribution` または `cloudfront:CreateDistribution` – ディストリビューションを更新または作成するアクセス許可を付与します。

詳細については、以下の各トピックを参照してください。
+ [Amazon CloudFront のアイデンティティとアクセス管理](security-iam.md)
+ 「*AWS Lambda デベロッパーガイド*」の「[Lambda リソースのアクセス許可](https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role)」

## サービスプリンシパルの関数実行ロール
<a name="lambda-edge-permissions-function-execution"></a>

ユーザーの関数を実行するときに `lambda.amazonaws.com` と `edgelambda.amazonaws.com` サービスプリンシパル が引き受けることができる IAM ロールを作成する必要があります。

**ヒント**  
Lambda コンソールで関数を作成する場合、AWS ポリシーテンプレートを使用して新しい実行ロールを作成することを選択できます。このステップでは、関数を実行するために必要な Lambda@Edge アクセス許可が*自動的に*追加されます。[チュートリアル: シンプルな Lambda@Edge 関数の作成のステップ 5](lambda-edge-how-it-works-tutorial.md#lambda-edge-how-it-works-tutorial-create-function) を参照してください。

IAM ロールを手動で作成する詳細については、「*IAM ユーザーガイド*」の「[ロールの作成とポリシーのアタッチ (コンソール)](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions_create-policies.html)」を参照してください。

**Example 例: ロール信頼ポリシー**  
IAM コンソールの **[信頼関係]** タブで、このロールを追加できます。このポリシーは **[アクセス許可]** タブには追加しないでください。    
****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": {
            "Service": [
               "lambda.amazonaws.com",
               "edgelambda.amazonaws.com"
            ]
         },
         "Action": "sts:AssumeRole"
      }
   ]
}
```

実行ロールに付与する必要がある許可の詳細については、「*AWS Lambda デベロッパーガイド*」の「[Lambda リソースのアクセス許可](https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role)」を参照してください。

**注意事項**  
デフォルトでは、CloudFront イベントが Lambda 関数をトリガーするたびに、データが CloudWatch Logs に書き込まれます。これらのログを使用する場合は、CloudWatch Logs にデータを書き込むためのアクセス権限が実行ロールに必要です。事前定義された AWSLambdaBasicExecutionRole を使用して、実行ロールにアクセス許可を付与できます。  
CloudWatch Logs の詳細については、「[エッジ関数のログ](edge-functions-logs.md)」を参照してください。
S3 バケットからのオブジェクトの読み取りなど、Lambda 関数コードが他の AWS リソースにアクセスする場合、そのアクションを実行するためのアクセス許可が実行ロールに必要です。

## Lambda@Edge 用のサービスにリンクされたロール
<a name="using-service-linked-roles-lambda-edge"></a>

Lambda@Edge は IAM [サービスリンクロール](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-service-linked-role)を使用します。サービスにリンクされたロールは、サービスに直接リンクされた一意のタイプの IAM ロールです。サービスにリンクされたロールは、サービスによって事前定義されており、お客様の代わりにサービスから他の AWS サービスを呼び出す必要のあるアクセス許可がすべて含まれています。

Lambda@Edge は、以下の IAM サービスリンクロールを使用します。
+ **AWSServiceRoleForLambdaReplicator** - Lambda@Edge はこのロールを使用して、Lambda@Edge が関数を AWS リージョン にレプリケートできるようにします。

  CloudFront で Lambda@Edge トリガーを初めて追加すると、AWSServiceRoleForLambdaReplicator という名前のロールが自動的に作成され、Lambda@Edge が関数を AWS リージョン にレプリケートできるようになります。このロールは、Lambda@Edge 関数を使用するために必要です。AWSServiceRoleForLambdaReplicator ロールの ARN は次の例のようになります。

  `arn:aws:iam::123456789012:role/aws-service-role/replicator.lambda.amazonaws.com/AWSServiceRoleForLambdaReplicator`
+ **AWSServiceRoleForCloudFrontLogger** – CloudFront はこのロールを使用してログファイルを CloudWatch にプッシュします。ログファイルを使用して Lambda@Edge 検証エラーをデバッグできます。

  Lambda@Edge 関数の関連付けを追加すると、AWSServiceRoleForCloudFrontLogger ロールが自動的に作成され、CloudFront が Lambda@Edge エラーログファイルを CloudWatch にプッシュできるようになります。AWSServiceRoleForCloudFrontLogger の ARN は次のようになります。

  `arn:aws:iam::account_number:role/aws-service-role/logger.cloudfront.amazonaws.com/AWSServiceRoleForCloudFrontLogger`

サービスリンクロールを使用することで、必要なアクセス許可を手動で追加する必要がなくなるため、Lambda@Edge のセットアップと使用が簡単になります。Lambda@Edge はそのサービスリンクロールのアクセス許可を定義し、Lambda@Edge のみがそのロールを引き受けることができます。定義されたアクセス権限には、信頼ポリシーとアクセス権限ポリシーが含まれます。その他の IAM エンティティにアクセス許可ポリシーをアタッチすることはできません。

サービスにリンクされたロールを削除するには、その前に、それらのロールに関連付けられている CloudFront または Lambda@Edge のリソースを削除する必要があります。このようにして、アクティブなリソースにアクセスするためにまだ必要な、サービスリンクロールを削除しないようにすることで、Lambda@Edge リソースが保護されます。

サービスにリンクされたロールの詳細については、「[CloudFront のサービスにリンクされたロール](security_iam_service-with-iam.md#security_iam_service-with-iam-roles-service-linked)」を参照してください。

### Lambda@Edge 用のサービスにリンクされたロールのアクセス許可
<a name="slr-permissions-lambda-edge"></a>

Lambda@Edge は、**AWSServiceRoleForLambdaReplicator** および **AWSServiceRoleForCloudFrontLogger** という名前の 2 つのサービスにリンクされたロールを使用します。以下のセクションでは、それらの各ロールのアクセス許可を管理する方法について説明します。

**Contents**
+ [Lambda Replicator 用のサービスにリンクされたロールのアクセス許可](#slr-permissions-lambda-replicator)
+ [CloudFront ロガー用のサービスにリンクされたロールのアクセス許可](#slr-permissions-cloudfront-logger)

#### Lambda Replicator 用のサービスにリンクされたロールのアクセス許可
<a name="slr-permissions-lambda-replicator"></a>

このサービスにリンクされたロールにより、Lambda が Lambda@Edge 関数を AWS リージョン にレプリケートできるようになります。

AWSServiceRoleForLambdaReplicator サービスにリンクされたロールは、ロールを継承するために `replicator.lambda.amazonaws.com` のサービスを信頼します。

このロールのアクセス権限ポリシーは、Lambda@Edge が以下のアクションを指定されたリソースに対して実行することを許可します。
+ `lambda:CreateFunction` の。`arn:aws:lambda:*:*:function:*`
+ `lambda:DeleteFunction` の。`arn:aws:lambda:*:*:function:*`
+ `lambda:DisableReplication` の。`arn:aws:lambda:*:*:function:*`
+ `iam:PassRole` の。`all AWS resources`
+  `cloudfront:ListDistributionsByLambdaFunction` の。`all AWS resources`

#### CloudFront ロガー用のサービスにリンクされたロールのアクセス許可
<a name="slr-permissions-cloudfront-logger"></a>

このサービスリンクロールでは、Lambda@Edge の検証エラーをデバッグするのに役立つように CloudFront が CloudWatch にログファイルをプッシュすることが許可されます。

AWSServiceRoleForCloudFrontLogger サービスにリンクされたロールは、ロールを継承するために `logger.cloudfront.amazonaws.com` のサービスを信頼します。

このロールのアクセス権限ポリシーは、Lambda@Edge が以下のアクションを指定された `arn:aws:logs:*:*:log-group:/aws/cloudfront/*` リソースに対して実行することを許可します。
+ `logs:CreateLogGroup` ``
+ `logs:CreateLogStream`
+ `logs:PutLogEvents`

IAM エンティティ (ユーザー、グループ、ロールなど) で Lambda@Edge のサービスにリンクされたロールを削除できるように、アクセス許可を設定する必要があります。詳細については*IAM ユーザーガイド* の「[サービスにリンクされた役割のアクセス許可](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html#service-linked-role-permissions)」を参照してください。

### Lambda@Edge 用のサービスにリンクされたロールの作成
<a name="create-slr-lambda-edge"></a>

通常、Lambda@Edge のサービスにリンクされたロールを手動で作成することはありません。以下のシナリオで、サービスによってロールが自動的に作成されます。
+ トリガーを初めて作成するとき、サービスは AWSServiceRoleForLambdaReplicator ロールを作成します (まだ存在しない場合）。このロールにより、Lambda が Lambda@Edge 関数を AWS リージョン にレプリケートできるようになります。

  このサービスにリンクされたロールを削除した場合、Lambda@Edge の新しいトリガーをディストリビューションに追加すると、そのロールは再び作成されます。
+ Lambda@Edge が関連付けられた CloudFront ディストリビューションを更新または作成すると、サービスによって AWSServiceRoleForCloudFrontLogger ロールが作成されます (まだ存在しない場合)。このロールにより、CloudFront が CloudWatch にログファイルをプッシュできるようになります。

  このサービスリンクロールを削除した場合は、Lambda@Edge の関連付けがある CloudFront ディストリビューションを更新または作成すると、そのロールが再び作成されます。

これらのサービスリンクロールを手動で作成する必要がある場合は、次の AWS Command Line Interface (AWS CLI) コマンドを実行します。

**AWSServiceRoleForLambdaReplicator ロールを作成するには**
+ 以下のコマンドを実行してください。

  ```
  aws iam create-service-linked-role --aws-service-name replicator.lambda.amazonaws.com
  ```

**AWSServiceRoleForCloudFrontLogger ロールを作成するには**
+ 以下のコマンドを実行してください。

  ```
  aws iam create-service-linked-role --aws-service-name logger.cloudfront.amazonaws.com
  ```

### Lambda@Edge のサービスにリンクされたロールの編集
<a name="edit-slr-lambda-edge"></a>

Lambda@Edge のサービスリンクロール AWSServiceRoleForLambdaReplicator または AWSServiceRoleForCloudFrontLogger を編集することはできません。サービスによってサービスリンクロールが作成された後は、多くのエンティティでそのロールが参照されるため、そのロール名は変更できません。ただし、IAM を使用してロールの説明を編集することはできます。詳細については、「*IAM ユーザーガイド*」の「[サービスリンクロールの編集](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html#edit-service-linked-role)」を参照してください。

### Lambda@Edge サービスリンクロールでサポートされている AWS リージョン
<a name="slr-regions-lambda-edge"></a>

CloudFront は、次の AWS リージョン で Lambda@Edge 用のサービスにリンクされたロールの使用をサポートしています。
+ 米国東部 (バージニア北部) – `us-east-1`
+ 米国東部 (オハイオ) – `us-east-2`
+ 米国西部 (北カリフォルニア) – `us-west-1`
+ 米国西部 (オレゴン) – `us-west-2`
+ アジアパシフィック (ムンバイ) – `ap-south-1`
+ アジアパシフィック (ソウル) – `ap-northeast-2`
+ アジアパシフィック (シンガポール) – `ap-southeast-1`
+ アジアパシフィック (シドニー) – `ap-southeast-2`
+ アジアパシフィック (東京) – `ap-northeast-1`
+ 欧州 (フランクフルト) – `eu-central-1`
+ 欧州 (アイルランド) – `eu-west-1`
+ 欧州 (ロンドン) – `eu-west-2`
+ 南米 (サンパウロ) – `sa-east-1`

# Lambda@Edge 関数を記述および作成する
<a name="lambda-edge-create-function"></a>

Lambda@Edge を使用するには、AWS Lambda 関数のコードを*記述*します。Lambda@Edge 関数の記述については、以下のリソースを参照してください。
+  [Lambda@Edge イベント構造](lambda-event-structure.md) – Lambda@Edge で使用するイベント構造を理解します。
+ [Lambda@Edge 関数の例](lambda-examples.md) – A/B テストや HTTP リダイレクトの生成などの関数の例。

Lambda@Edge で Node.js または Python を使用するためのプログラミングモデルは、AWS リージョン で Lambda を使用するプログラミングモデルと同じです。詳細については、「*AWS Lambda デベロッパーガイド*」の「[Node.js を使用した Lambda 関数の作成](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html)」または「[Python を使用した Lambda 関数の作成](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python.html)」を参照してください。

Lambda@Edge 関数で、`callback` パラメータを含めて、リクエストまたはレスポンスイベントの該当するオブジェクトを返します。
+ **リクエストイベント** - レスポンスに `cf.request` オブジェクトを含めます。

  レスポンスを生成している場合は、レスポンスに `cf.response` オブジェクトを含めます。詳細については、「[リクエストトリガーでの HTTP レスポンスを生成する](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests)」を参照してください。
+ **レスポンスイベント** - レスポンスに `cf.response` オブジェクトを含めます。

独自のコードを記述するか、いずれかの例を使用した後で、Lambda で関数を作成します。関数を作成したり、既存の関数を編集したりするには、以下のトピックを参照してください。

**Topics**
+ [Lambda@Edge 関数を作成する](lambda-edge-create-in-lambda-console.md)
+ [Lambda 関数を編集する](lambda-edge-edit-function.md)

 Lambda で関数を作成したら、トリガーと呼ばれる特定の CloudFront イベントに基づいて関数を実行するように Lambda を設定します。**詳細については、「[Lambda@Edge 関数のトリガーを追加する](lambda-edge-add-triggers.md)」を参照してください。

# Lambda@Edge 関数を作成する
<a name="lambda-edge-create-in-lambda-console"></a>

CloudFront イベントに基づく Lambda 関数を実行するように AWS Lambda をセットアップするには、この手順を実行します。<a name="lambda-edge-create-function-procedure"></a>

**ターゲットの Lambda@Edge 関数を作成するには**

1. AWS マネジメントコンソール にサインインして AWS Lambda コンソール ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) を開きます。

1. 1 つ以上の Lambda 関数が既にある場合は、[**Create function**] を選択します。

   関数がない場合は、[**Get Started Now**] を選択します。

1. ページの上部にあるリージョンのリストで、[**米国東部 (バージニア北部)**] を選択します。

1. 独自のコードを使用して関数を作成するか、CloudFront の設計図で始まる関数を作成します。
   + 独自のコードを使用して関数を作成するには、[**Author from scratch**] を選択します。
   + CloudFront のブループリントを一覧表示するには、フィルタフィールドに「**cloudfront**」と入力し、**Enter** キーを選択します。

     使用するブループリントを見つけたら、ブループリントの名前を選択します｡

1. **[基本情報]** セクションで、以下の値を指定します。

   1. **名前** - 関数の名前を入力します。

   1. **ロール** – すぐに開始するには、**[テンプレートから新しいロールを作成する複数]** を選択します。**[既存のロールを選択]** または **[カスタムロールを作成]** を選択し、プロンプトに従ってこのセクションの情報を完了することもできます。

   1. **ロール名** - ロールの名前を入力します。

   1. **ポリシーテンプレート** – **[基本的な Edge Lambda のアクセス許可]** を選択します。

1. ステップ 4 で [**Author from scratch**] を選択した場合は、ステップ 7 に進んでください。

   ステップ 4 で設計図を選択した場合は、[**cloudfront**] セクションで、この関数を CloudFront ディストリビューションおよび CloudFront イベントのキャッシュに関連付ける 1 つのトリガーを作成できます。この時点で [**Remove**] を選択することをお勧めします。そのため、関数の作成時にトリガーはありません。後でトリガーを追加できます。
**ヒント**  
トリガーを追加する前に、関数をテストおよびデバッグすることをお勧めします。代わりにトリガーを追加する場合、関数を作成するとすぐに関数が実行され、世界各地の AWS ロケーションへのレプリケーションが完了し、対応するディストリビューションがデプロイされます。

1. [**関数の作成**] を選択します。

   Lambda は関数 \$1LATEST とバージョン 1 の 2 つのバージョンを作成します。\$1LATEST バージョンのみを編集できますが、コンソールに最初はバージョン 1 が表示されます。

1. 関数を編集するには、関数の ARN の下にあるページの上部にある [**Version 1**] を選択します。次に [**Versions**] タブで [**\$1LATEST**] を選択します。(その関数をそのままにしてから戻った場合、ボタンラベルは [**Qualifiers**] となります)。

1. [**Configuration**] タブで、該当する [**Code entry type**] を選択します。次に、プロンプトに従ってコードを編集またはアップロードします。

1. [**ランタイム**] で、関数のコードに基づいて値を選択します。

1. [**Tags**] セクションで、該当するタグを追加します。

1. [**Actions**] を選択し、[**Publish new version**] を選択します。

1. 新しいバージョンの関数に関する説明を入力します。

1. [**Publish**] を選択します。

1. 関数をテストおよびデバッグします。Lambda コンソールでのテストの詳細については、「AWS Lambda 開発者ガイド」の「[コンソールを使用して Lambda 関数を呼び出す](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html#get-started-invoke-manually)」を参照してください。**

1. CloudFront イベントに対して関数を実行する準備ができたら、別のバージョンを公開し、トリガーを追加する関数を編集します。詳細については、「[Lambda@Edge 関数のトリガーを追加する](lambda-edge-add-triggers.md)」を参照してください。

# Lambda 関数を編集する
<a name="lambda-edge-edit-function"></a>

Lambda@Edge 関数を作成したら、Lambda コンソールを使用して関数を編集できます。

**注意事項**  
元のバージョンのラベルは [\$1LATEST] です。
\$1LATEST バージョンのみを編集できます。
\$1LATEST バージョンを編集するたびに、新しい番号付きバージョンを公開する必要があります。
\$1LATEST のトリガーを作成することはできません。
新しいバージョンの関数を発行する場合、Lambda は以前のバージョンから新しいバージョンにトリガーを自動的にコピーしません。新しいバージョン用のトリガーを再現する必要があります。
CloudFront イベントのトリガーを関数に追加する場合、同じディストリビューション、キャッシュ動作、および同じ関数の以前のバージョン用のイベント用のトリガーが既に存在している場合、Lambda は以前のバージョンからトリガーを削除します。
トリガーを追加するなど、CloudFront ディストリビューションを更新した後で、トリガーで指定した関数が機能する前に、変更がエッジロケーションに伝達されるのを待つ必要があります。<a name="lambda-edge-edit-function-procedure"></a>

**Lambda 関数を編集するには**

1. AWS マネジメントコンソール にサインインして AWS Lambda コンソール ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) を開きます。

1. ページの上部にあるリージョンのリストで、[**米国東部 (バージニア北部)**] を選択します。

1. 関数のリストで、関数の名前を選択します。

   デフォルトでは、\$1LATEST バージョンがコンソールに表示されます。以前のバージョンを表示することはできますが ([**Qualifiers**] を選択します)、編集できるのは \$1LATEST のみです。

1. [**Code (コード)**] タブの [**Code entry type (コードの入力タイプ)**] で、ブラウザでのコードの編集、.zip ファイルのアップロード、または Amazon S3 からのファイルのアップロードを選択します。

1. [**Save**] または [**Save and test**] を選択します。

1. [**Actions**] を選択し、[**Publish new version**] を選択します。

1. [**Publish new version from \$1LATEST**] ダイアログボックスで、新しいバージョンの説明を入力します。この説明は、自動的に生成されたバージョン番号とともにバージョンのリストに表示されます。

1. [**Publish**] を選択します。

   新しいバージョンが自動的に最新バージョンになります。バージョン番号はページの左上隅にある **[バージョン]**に表示されます。
**注記**  
関数のトリガーをまだ追加していない場合は、「[Lambda@Edge 関数のトリガーを追加する](lambda-edge-add-triggers.md)」を参照してください。

1. [**Triggers**] タブを選択します。

1. [**Add trigger**] を選択します。

1. [**Add trigger (トリガーの追加)**] ダイアログボックスでチェックボックスをオンにし、[**CloudFront**] を選択します。
**注記**  
関数の 1 つまたは複数のトリガーを作成済みの場合、CloudFront がデフォルトのサービスになります。

1. Lambda 関数をいつ実行するかを示す、次の値を指定します。

   1. **ディストリビューション ID **– トリガーの追加先となるディストリビューションの ID を選択します。

   1. **キャッシュ動作** – 関数を実行するオブジェクトを指定するキャッシュ動作を選択します。

   1. **CloudFront イベント** – 関数を実行させる CloudFront イベントを選択します。

   1. **Enable trigger and replicate** – このチェックボックスをオンにし、Lambda が関数を AWS リージョン に対してグローバルにレプリケートするようにします。

1. **[送信]** を選択します。

1. この関数のトリガーをさらに追加するには、ステップ 10～13 を繰り返します。

Lambda コンソールで関数をテストおよびデバッグする方法の詳細については、「AWS Lambda 開発者ガイド」の「[コンソールを使用して Lambda 関数を呼び出す](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html#get-started-invoke-manually)」を参照してください。**

CloudFront イベントに対して関数を実行する準備ができたら、別のバージョンを公開し、トリガーを追加する関数を編集します。詳細については、「[Lambda@Edge 関数のトリガーを追加する](lambda-edge-add-triggers.md)」を参照してください。

# Lambda@Edge 関数のトリガーを追加する
<a name="lambda-edge-add-triggers"></a>

Lambda@Edge トリガーは、CloudFront ディストリビューション、キャッシュ動作、および関数を実行させるイベントの 1 つの組み合わせです。例えば、ディストリビューション用に設定した特定のキャッシュ動作について、CloudFront がビューワーからリクエストを受け取ったときに関数を実行させるトリガーを作成できます。1 つ以上の CloudFront トリガーを指定できます。

**ヒント**  
CloudFront ディストリビューションを作成するときは、別のリクエストを受け取ったときに応答する方法を CloudFront に指示する設定を指定します。デフォルトの設定は、ディストリビューションの*デフォルトのキャッシュ動作*と呼ばれます。特定のファイルタイプのリクエストを受け取る場合など、特定の状況での CloudFront の応答方法を定義する追加のキャッシュ動作を設定できます。詳細については、「[キャッシュ動作の設定](DownloadDistValuesCacheBehavior.md)」を参照してください。

Lambda 関数を最初に作成するときは、1 つのトリガーのみを指定できます。**Lambda コンソールを使用するか、CloudFront コンソールでディストリビューションを編集するかで、後で同じ関数にさらにトリガーを追加できます。
+ Lambda コンソールは、同じ CloudFront ディストリビューションの関数にトリガーを追加する場合に適しています。
+ 更新するディストリビューションを見つけやすいため、複数のディストリビューションのトリガーを追加する場合は、CloudFront コンソールが適しています。同時に他の CloudFront 設定を更新することもできます。

**Topics**
+ [Lambda@Edge 関数をトリガーできる CloudFront イベント](lambda-cloudfront-trigger-events.md)
+ [イベントを選択して関数をトリガーする](lambda-how-to-choose-event.md)
+ [Lambda@Edge 関数にトリガーを追加する (コンソール)](lambda-edge-add-triggers-console.md)

# Lambda@Edge 関数をトリガーできる CloudFront イベント
<a name="lambda-cloudfront-trigger-events"></a>

Amazon CloudFront ディストリビューションの各キャッシュ動作に、特定の CloudFront イベントの発生時に Lambda 関数を実行させるトリガー (関連付け) を 4 つまで追加できます。CloudFront トリガーは、次の図に示す、4 つの CloudFront イベントのいずれかに基づくことができます。

![\[Lambda 関数の CloudFront トリガーイベントが CloudFront と統合する仕組みを示す概念的なグラフィック。\]](http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/images/cloudfront-events-that-trigger-lambda-functions.png)


Lambda@Edge 関数のトリガーに使用できる CloudFront イベントには、以下のものがあります。

**ビューワーリクエスト**  
CloudFront がビューワーからリクエストを受け取ると、リクエストされたオブジェクトが CloudFront キャッシュにあるかどうかを確認する前に関数が実行されます。  
次の場合には関数は実行されません。  
+ カスタムエラーページを取得する場合。
+ CloudFront で HTTP リクエストが自動的に HTTPS にリダイレクトされる場合 ([[ビューワープロトコルポリシー](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy)] の値が **[Redirect HTTP to HTTPS]** の場合)

**オリジンリクエスト**  
CloudFront がリクエストをオリジンに転送したときに*のみ*、関数が実行されます。リクエストされたオブジェクトが CloudFront キャッシュ内にある場合、関数は実行されません。

**オリジンレスポンス**  
CloudFront がオリジンからのレスポンスを受け取った後、レスポンス内のオブジェクトをキャッシュする前に関数が実行されます。関数は、オリジンからエラーが返された場合でも実行されることに注意してください。  
次の場合には関数は実行されません。  
+ リクエストされたファイルが CloudFront キャッシュ内にあり、その有効期限が切れていない場合。
+ オリジンリクエストイベントによってトリガーされた関数からレスポンスが生成された場合。

**ビューワーレスポンス**  
リクエストされたファイルがビューワーに返される前に関数が実行されます。ファイルが CloudFront キャッシュ内に既に存在するかどうかに関係なく、関数が実行されることに注意してください。  
次の場合には関数は実行されません。  
+ オリジンが HTTP ステータスコードとして 400 以上を返した場合。
+ カスタムエラーページが返された場合。
+ ビューワーリクエストイベントによってトリガーされた関数からレスポンスが生成された場合。
+ CloudFront で HTTP リクエストが自動的に HTTPS にリダイレクトされる場合 ([[ビューワープロトコルポリシー](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy)] の値が [**Redirect HTTP to HTTPS**] の場合)

同じキャッシュ動作に複数のトリガーを追加する場合、各トリガーに対して同じ関数を実行することも、異なる関数を実行することもできます。また、複数のディストリビューションに同じ関数を関連付けることもできます。

**注記**  
CloudFront イベントが Lambda 関数の実行をトリガーすると、その関数が終了するまで CloudFront は続行できません。**  
例えば、CloudFront ビューワーリクエストイベントによって Lambda 関数がトリガーされると、その Lambda 関数が実行を終了するまで、CloudFront からビューワーにレスポンスは返されず、リクエストはオリジンに転送されません。  
つまり、Lambda 関数をトリガーするリクエストごとにリクエストのレイテンシーが長くなるため、関数をできるだけ速く実行する必要があります。

# イベントを選択して関数をトリガーする
<a name="lambda-how-to-choose-event"></a>

Lambda 関数をトリガーするために使用する CloudFront イベントを決定する際には、次の点を考慮してください。

**Lambda 関数によって変更されたオブジェクトを CloudFront でキャッシュする場合**  
Lambda 関数によって変更されたオブジェクトを CloudFront でキャッシュして、そのオブジェクトが次回にリクエストされたときにエッジロケーションから提供できるようにする場合は、オリジンリクエストイベントまたはオリジンレスポンスイベントを使用します。****  
これにより、オリジンの負荷と以降のリクエストのレイテンシーが軽減され、以降のリクエストで Lambda@Edge を呼び出すコストが削減されます。  
例えば、オリジンから返されたオブジェクトのヘッダーを追加、削除、または変更する場合に、その結果を CloudFront でキャッシュするには、オリジンレスポンスイベントを使用します。

**すべてのリクエストに対して関数を実行する場合**  
CloudFront が受信したディストリビューションのすべてのリクエストに対して関数を実行する場合は、ビューワーリクエストイベントまたはビューワーレスポンスイベントを使用します。****  
オリジンリクエストイベントとオリジンレスポンスイベントは、リクエストされたオブジェクトがエッジロケーションにキャッシュされておらず、CloudFront がリクエストをオリジンに転送する場合にだけ発生します。

**関数でキャッシュキーを変更する場合**  
キャッシュの基準として使用している値を変更する場合は、ビューワーリクエストイベントを使用します。**  
たとえば、関数で URL を変更してパスに言語の省略形を含める場合 (ユーザーがドロップダウンリストから言語を選択した場合など) は、ビューワーリクエストイベントを使用します。  
+ **ビューワーリクエストの URL** - https://example.com/en/index.html
+ **リクエストがドイツの IP アドレスから送られてきた場合の URL** - https://example.com/de/index.html
Cookie またはリクエストヘッダーをキャッシュ条件として使用している場合もビューワーリクエストイベントを使用します。  
関数で Cookie またはヘッダーを変更する場合は、リクエストの該当部分をオリジンに転送するように CloudFront を設定します。詳細については、以下の各トピックを参照してください。  
+ [Cookie に基づいてコンテンツをキャッシュする](Cookies.md)
+ [リクエストヘッダーに基づいてコンテンツをキャッシュする](header-caching.md)

**関数がオリジンからのレスポンスに影響を与える**  
オリジンからのレスポンスに影響を与えるような方法でリクエストを変更するには、オリジンリクエストイベントを使用します。**  
通常、ほとんどのビューワーリクエストイベントはオリジンに転送されません。CloudFront は、エッジキャッシュに既に存在するオブジェクトを使用してリクエストに応答します。オリジンリクエストイベントに基づく関数でリクエストを変更すると、変更されたオリジンリクエストに対するレスポンスが CloudFront でキャッシュされます。

# Lambda@Edge 関数にトリガーを追加する (コンソール)
<a name="lambda-edge-add-triggers-console"></a>

AWS Lambda コンソールまたは Amazon CloudFront コンソールのいずれかを使用して、Lambda@Edge 関数のトリガーを追加できます。

**重要**  
トリガーは、関数の番号付きバージョン (**\$1LATEST** ではなく) に対してのみ作成できます。

------
#### [ Lambda console ]<a name="lambda-edge-add-triggers-procedure"></a>

**CloudFront イベントのトリガーを Lambda@Edge 関数に追加するには**

1. AWS マネジメントコンソール にサインインして AWS Lambda コンソール ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) を開きます。

1. ページの上部にあるリージョンのリストで、[**米国東部 (バージニア北部)**] を選択します。

1. [**Functions**] ページで、トリガーを追加する関数の名前を選択します。

1. **[関数の概要]** ページで、**[バージョン]** タブを選択します。

1. トリガーを追加するバージョンを選択します。

   バージョンを選択すると、ボタンの名前が [**Version: \$1LATEST**] または [**Version:*** バージョン番号*] に変わります。

1. [**Triggers**] タブを選択します。

1. [**Add trigger**] を選択します。

1. **[トリガー設定]** で、**[ソースを選択]** を選択し、**cloudfront** と入力し、**CloudFront** を選択します。
**注記**  
1 つまたは複数のトリガーを作成済みの場合、CloudFront がデフォルトのサービスになります。

1. Lambda 関数をいつ実行するかを示す、次の値を指定します。

   1. **ディストリビューション** – トリガーを追加するディストリビューションを選択します。

   1. **キャッシュ動作** – 関数を実行するオブジェクトを指定するキャッシュ動作を選択します。
**注記**  
キャッシュ動作に `*` を指定すると、Lambda 関数はデフォルトのキャッシュ動作にデプロイされます。

   1. **CloudFront イベント** – 関数を実行させる CloudFront イベントを選択します。

   1. **本文を含める** – 関数のリクエストボディにアクセスするには、このチェックボックスをオンにします。

   1. **Lambda@Edge へのデプロイを確認** – このチェックボックスをオンにして、AWS Lambda が関数を AWS リージョン にグローバルにレプリケートするようにします。

1. **[Add]** (追加) を選択します。

   この関数は、更新された CloudFront ディストリビューションがデプロイされたときに、指定された CloudFront イベントのリクエストの処理を開始します。ディストリビューションがデプロイされているかどうかを確認するには、ナビゲーションペインで [**Distributions**] を選択します。ディストリビューションをデプロイすると、ディストリビューションの **[ステータス]** 列の値が、**[デプロイ中]** からデプロイの日時に変わります。

------
#### [ CloudFront console ]<a name="lambda-create-functions-add-triggers-cloudfront-console-procedure"></a>

**CloudFront イベントのトリガーを Lambda@Edge 関数に追加するには**

1. トリガーを追加する Lambda 関数の ARN を取得します。

   1. AWS マネジメントコンソール にサインインして AWS Lambda コンソール ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) を開きます。

   1. ページの上部にあるリージョンのリストで、[**米国東部 (バージニア北部)**] を選択します。

   1. 関数のリストで、トリガーを追加する関数の名前を選択します。

   1. **[関数の概要]** ページで **[バージョン]** タブを選択し、トリガーを追加する先の番号付きバージョンを選択します。

   1. **[ARN をコピー]** ボタンを選択して、ARN をクリップボードにコピーします。Lambda 関数の ARN は次のようになります。

      `arn:aws:lambda:us-east-1:123456789012:function:TestFunction:2`

      末尾の番号 (この例では **2**) は関数のバージョン番号です。

1.  で CloudFront コンソールを開きます[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)

1. ディストリビューションのリストで、トリガーを追加するディストリビューションの ID を選択します。

1. [**Behaviors**] タブを選択します。

1. トリガーを追加する先のキャッシュ動作を選択し、**[編集]** を選択します。

1. **[関数の関連付け]** で、**[関数タイプ]** リストから **[Lambda@Edge]** を選択し、ビューワーリクエスト、ビューワーレスポンス、オリジンリクエスト、またはオリジンレスポンスに対して関数をいつ実行するかを選択します。

   詳細については、「[イベントを選択して関数をトリガーする](lambda-how-to-choose-event.md)」を参照してください。

1. **[関数 ARN/名前]** テキストボックスに、選択したイベントの発生時に実行する Lambda 関数の ARN を貼り付けます。これは Lambda コンソールからコピーした値です。

1. 関数のリクエスト本文にアクセスする場合は、**[本文を含める]** を選択します。

   リクエスト本文を置き換えるだけの場合は、このオプションを選択する必要はありません。

1. 他のイベントタイプで同じ関数を実行するには、ステップ 6 と 7 を繰り返します。

1. **[Save changes]** (変更の保存) をクリックします。

1. このディストリビューションの他のキャッシュ動作にトリガーを追加するには、ステップ 5～10 を繰り返します。

   この関数は、更新された CloudFront ディストリビューションがデプロイされたときに、指定された CloudFront イベントのリクエストの処理を開始します。ディストリビューションがデプロイされているかどうかを確認するには、ナビゲーションペインで [**Distributions**] を選択します。ディストリビューションをデプロイすると、ディストリビューションの **[ステータス]** 列の値が、**[デプロイ中]** からデプロイの日時に変わります。

------

# Lambda@Edge 関数をテストおよびデバッグする
<a name="lambda-edge-testing-debugging"></a>

Lambda@Edge 関数コードのスタンドアロンをテストすること、目的のタスクの完了を確認すること、統合のテストを行うこと、CloudFront で関数が正しく機能しているか確認することは重要です。

統合テスト中または関数がデプロイされた後に、HTTP 5xx エラーなどの CloudFront エラーのデバッグが必要になることがあります。エラーは、Lambda 関数から返される無効なレスポンス、関数がトリガーされるときの実行時のエラー、または Lambda サービスによる実行スロットリングが原因のエラーの可能性があります。このトピックのセクションでは、どのタイプの障害が問題であるかを判別するための戦略、そしてその問題を解決するためのステップを共有します。

**注記**  
エラーをトラブルシューティングするときに CloudWatch ログファイルまたはメトリクスを確認する場合は、関数が実行される場所に最も近い AWS リージョン に表示または保存されていることに注意してください。したがって、例えば英国のユーザーがいるウェブサイトまたはウェブアプリケーションで、ディストリビューションに関連する Lambda 関数がある場合は、リージョンを変更してロンドン AWS リージョン の CloudWatch メトリクスまたはログファイルを表示する必要があります。詳細については、「[Lambda@Edge リージョンを判断する](#lambda-edge-testing-debugging-determine-region)」を参照してください。

**Topics**
+ [Lambda@Edge 関数をテストする](#lambda-edge-testing-debugging-test-function)
+ [CloudFront での Lambda@Edge 関数エラーを識別する](#lambda-edge-identifying-function-errors)
+ [無効な Lambda@Edge 関数レスポンス (検証エラー) のトラブルシューティング](#lambda-edge-testing-debugging-troubleshooting-invalid-responses)
+ [Lambda@Edge 関数実行エラーをトラブルシューティングする](#lambda-edge-testing-debugging-execution-errors)
+ [Lambda@Edge リージョンを判断する](#lambda-edge-testing-debugging-determine-region)
+ [アカウントがログを CloudWatch にプッシュするかどうかを判断する](#lambda-edge-testing-debugging-cloudwatch-logs-enabled)

## Lambda@Edge 関数をテストする
<a name="lambda-edge-testing-debugging-test-function"></a>

Lambda 関数をテストするには、スタンドアロンテストと統合テストの 2 つのステップがあります。

**スタンドアロン機能のテスト**  
CloudFront に Lambda 関数を追加する前に、Lambda コンソールでテスト機能を使用するか他の方法を使用して、必ず最初に機能をテストしてください。Lambda コンソールでのテストの詳細については、「AWS Lambda 開発者ガイド」の「[コンソールを使用して Lambda 関数を呼び出す](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html#get-started-invoke-manually)」を参照してください。**

**CloudFront での関数のオペレーションのテスト**  
統合テストを完了することが重要です。ここで、関数はディストリビューションに関連付けられ、CloudFront イベントに基づいて実行されます。関数が正しいイベントに対してトリガーされることを確認し、CloudFront に対して有効で正しいレスポンスを返します。例えば、イベント構造が正しいこと、有効なヘッダーだけが含まれていることなどを確認します。  
Lambda コンソールの関数で統合テストを繰り返す場合、コードを変更する際や関数を呼び出す CloudFront トリガーを変更する際は、Lambda@Edge チュートリアルのステップを参照しください。例えば、チュートリアルの「[ステップ 4: 関数を実行する CloudFront トリガーを追加する](lambda-edge-how-it-works-tutorial.md#lambda-edge-how-it-works-tutorial-add-trigger)」のステップで説明しているように、関数の番号付きバージョンを操作していることを確認します。  
変更を加えた場合やデプロイした場合、更新した関数と CloudFront トリガーがすべてのリージョンにレプリケートするまで数分かかることに注意してください。通常、これには数分かかりますが、最大で 15 分かかる場合があります。  
レプリケーションが終了したかどうかを確認するには、CloudFront コンソールに移動し、ディストリビューションを表示します。  

**レプリケーションのデプロイが完了したかどうかを確認するには**

1. CloudFront コンソール ([https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)) を開きます。

1. ディストリビューション名を選択します。

1. ディストリビューションのステータスが [**進行中**] から [**デプロイ済み**] に戻ったことを確認します。この場合、関数はレプリケートされたことを意味します。続いて、次のセクションのステップに従って関数が機能することを確認します。
コンソールでのテストでは関数のロジックのみを検証します。また、Lambda@Edge に固有のサービスクォータ (以前は制限と呼ばれていました) は適用されないことに注意してください。

## CloudFront での Lambda@Edge 関数エラーを識別する
<a name="lambda-edge-identifying-function-errors"></a>

関数のロジックが正常に機能することを確認した後でも、CloudFront での関数の実行時に HTTP 5xx エラーが発生することがあります。HTTP 5xx エラーはさまざまな理由で返される可能性があります。これには、Lambda 関数エラーやその他の CloudFront の問題が含まれる場合があります。
+ Lambda@Edge 関数を使用している場合は、CloudFront コンソールのグラフを使用してエラーの原因を突き止め、それを修正することができます。例えば、HTTP 5xx エラーの原因が CloudFront によるものか、Lambda 関数によるものかを確認し、特定の関数については関連するログファイルを表示して問題を調査できます。
+ HTTP エラー全般を CloudFront でトラブルシューティングするには、[CloudFront でのエラーレスポンスステータスコードのトラブルシューティング](troubleshooting-response-errors.md) のトピックのトラブルシューティング手順を参照してください。

### CloudFront で Lambda@Edge 関数エラーが発生する原因
<a name="lambda-edge-testing-debugging-function-errors"></a>

Lambda 関数が HTTP 5xx エラーの原因となる可能性がある理由はいくつかあります。実行するトラブルシューティングステップはエラーのタイプによって異なります。エラーは次のように分類されます。

**Lambda 関数実行エラー**  
関数に未処理の例外があるか、コードにエラーがあって CloudFront が Lambda からレスポンスを得られない場合は、実行エラーが発生します。たとえば、コードにコールバック (エラー) が含まれている場合です。

**無効な Lambda 関数のレスポンスが CloudFront に返される**  
関数の実行後、CloudFront が Lambda からレスポンスを受け取ります。レスポンスのオブジェクト構造が [Lambda@Edge イベント構造](lambda-event-structure.md) に従わない場合、またはレスポンスに無効なヘッダーや他の無効なフィールドが含まれている場合、エラーが返されます。

**CloudFront での実行は、Lambda サービスのクォータ (以前は制限と呼ばれていました) のために調整されます。**  
Lambda サービスは各リージョンでの実行を制限し、クォータに達するとエラーが返されます。詳細については、「[Lambda@Edge のクォータ](cloudfront-limits.md#limits-lambda-at-edge)」を参照してください。

### 障害のタイプを判断する方法
<a name="lambda-edge-testing-debugging-failure-type"></a>

デバッグするときにどこに焦点を合わせて CloudFront から返されたエラーを解決するかを決めるのに役立つように、なぜ CloudFront が HTTP エラーを返しているのかを識別することは役立ちます。これを開始するには、AWS マネジメントコンソール で CloudFront コンソールの [**Monitoring**] (モニタリング) セクションにあるグラフを使うことができます。CloudFront コンソールの [**Monitoring (モニタリング)**] セクションでのグラフ表示の詳細については、「[Amazon CloudWatch で CloudFront メトリクスをモニタリングする](monitoring-using-cloudwatch.md)」を参照してください。

次のグラフは、エラーが発生源によって返されたのか Lambda 関数によって返されたのかを追跡し、Lambda 関数からのエラーである場合に問題の種類を絞り込む場合に特に役立ちます。

**エラー率グラフ**  
各ディストリビューションの [**Overview**] タブに表示できるグラフの1つが、[**Error rates**] グラフです。このグラフは、ディストリビューションに対するすべてのリクエストに対するエラーの割合をパーセンテージで表示します。グラフは、Lambda 関数の合計エラー率、合計 4xx エラー、合計 5xx エラー、合計 5xx エラーを示しています。エラーの種類と量に基づいて、原因を調査してトラブルシューティングするための手順を実行できます。  

![\[CloudFront ディストリビューションのエラー率グラフ\]](http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/images/Distribution-error-rate-pct-full.png)

+ Lambda エラーが表示された場合は、関数が返す特定の種類のエラーを調べることで、さらに詳しく調べることができます。[**Lambda@Edge errors**] タブには、特定の関数に関する問題を特定するのに役立つように、関数エラーをタイプ別に分類したグラフが含まれています。
+ CloudFront エラーが表示された場合は、トラブルシューティングを行い、オリジンエラーを修正したり、CloudFront 設定を変更したりすることができます。詳細については、「[CloudFront でのエラーレスポンスステータスコードのトラブルシューティング](troubleshooting-response-errors.md)」を参照してください。

**Execution エラーと無効な関数レスポンスグラフ**  
[**Lambda@Edge errors**] タブには、特定のディストリビューションに対する Lambda@Edge エラーをタイプ別に分類したグラフが含まれています。例えば、1 つのグラフに AWS リージョン 別の実行エラーがすべて表示されます。  
問題のトラブルシューティングを容易にするために、地域別に特定の関数のログファイルを開いて調べることで、特定の問題を探すことができます。  

**リージョン別に特定の関数のログファイルを表示するには**

1. **[Lambda@Edge エラー]** タブの **[関連する Lambda@Edge 関数]** で、関数名を選択し、**[メトリクスの表示]** を選択します。

1. 次に、関数名のページの右上隅で、**[関数ログの表示]** を選択し、リージョンを選択します。

   例えば、米国西部 (オレゴン) リージョンの **[エラー]** グラフに問題が表示される場合は、ドロップダウンリストからそのリージョンを選択します。これにより、Amazon CloudWatch コンソールが開きます。

1. そのリージョンの CloudWatch コンソールの **[ログストリーム]** で、ログストリームを選択して関数のイベントを表示します。
さらに、トラブルシューティングとエラーの修正に関する推奨事項については、この章の次のセクションを参照してください。

**スロットルグラフ**  
[**Lambda@Edge errors**] タブには、[**Throttles**] グラフも含まれます。場合によっては、リージョンの同時実行性のクォータに達すると、Lambda サービスがリージョンごとに関数呼び出しを調整します。制限の超過エラーが表示される場合は、Lambda サービスがリージョンの実行に課すクォータに関数が達しています。クォータの増加をリクエストする方法など、詳細については、「[Lambda@Edge のクォータ](cloudfront-limits.md#limits-lambda-at-edge)」を参照してください。  

![\[Lambda@Edge 関数実行のスロットルグラフ。\]](http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/images/Lambda-throttles-page.png)


HTTP エラーのトラブルシューティングでこの情報を使用する方法の例については、「[AWS でコンテンツ配信をデバッグするための 4 つのステップ](https://aws.amazon.com/blogs/networking-and-content-delivery/four-steps-for-debugging-your-content-delivery-on-aws/)」を参照してください。

## 無効な Lambda@Edge 関数レスポンス (検証エラー) のトラブルシューティング
<a name="lambda-edge-testing-debugging-troubleshooting-invalid-responses"></a>

問題が Lambda 検証エラーであると特定した場合は、Lambda 関数が CloudFront に無効なレスポンスを返していることを意味します。このセクションのガイダンスに従い、関数を確認し、レスポンスが CloudFront 要件に従っていることを確認する手順を実行します。

CloudFront は、次の 2 つの方法で Lambda 関数からのレスポンスを検証します。
+ **Lambda レスポンスは、必要なオブジェクト構造に従う必要があります。**不正なオブジェクト構造の例には次のようなものがあります。解析できない JSON、必須フィールドの欠落、レスポンスの無効なオブジェクト。詳細については、「[Lambda@Edge イベント構造](lambda-event-structure.md)」を参照してください。
+ **レスポンスには有効なオブジェクト値のみを含める必要があります。**レスポンスに有効なオブジェクトが含まれるがサポートされていない値がある場合、エラーが発生します。例には、許可されていない、または読み取り専用のヘッダーの追加または更新 (「[エッジ関数に対する制限](edge-functions-restrictions.md)」を参照)、ボディサイズの上限の超過 (Lambda@Edge [エラー](lambda-generating-http-responses.md#lambda-generating-http-responses-errors) トピックの「*生成されるレスポンスのサイズに対する制限」を参照*)、および無効な文字または値 (「[Lambda@Edge イベント構造](lambda-event-structure.md)」を参照) などがあります。

Lambda が CloudFront に無効なレスポンスを返すと、Lambda 関数が実行されるリージョンで CloudFront が CloudWatch にプッシュするログファイルに、エラーメッセージが書き込まれます。これは、無効なレスポンスがあるときにログファイルを CloudWatch に送信するデフォルトの動作です。ただし、機能をリリースする前に Lambda 関数を CloudFront と関連付けると、関数に対して有効にならない可能性があります。詳細については、このトピックの後半の「*アカウントがログを CloudWatch にプッシュするかどうかを判断する*」を参照してください。

CloudFront は、関数を実行した場所に対応するリージョンで、ディストリビューションに関連するロググループにログファイルをプッシュします。ロググループの形式は `/aws/cloudfront/LambdaEdge/DistributionId` です。ここで *DistributionId* はディストリビューションの ID です。CloudWatch ログファイルがあるリージョンを決定するには、このトピックの後半の「*Lambda@Edge のリージョンの判別*」を参照してください。

再現可能なエラーの場合、エラーになる新しいリクエストを作成し、障害のある CloudFront レスポンス (`X-Amz-Cf-Id` ヘッダー) でリクエスト ID を見つけて、ログファイル内の 1 つの障害を特定します。ログファイルのエントリには、エラーが返される理由を特定するのに役立つ情報が含まれます。また、対応する Lambda リクエスト ID もリスト表示されるため、1 つのリクエストのコンテキストでの根本原因を分析することもできます。

エラーが断続的な場合は、CloudFront アクセスログを使用して障害が発生したリクエストのリクエスト ID を見つけ、対応するエラーメッセージの CloudWatch Logs を検索します。詳細については、前のセクションの「*Determining the Type of Failure*」を参照してください。

## Lambda@Edge 関数実行エラーをトラブルシューティングする
<a name="lambda-edge-testing-debugging-execution-errors"></a>

Lambda 実行エラーが問題である場合は、Lambda 関数のログ記録ステートメントを作成しておくと、CloudWatch での関数の実行をモニタリングする CloudFront ログファイルにメッセージを書き込み、正常に機能しているかどうかを判断するのに役立ちます。その後、これらのステートメントを CloudWatch ログファイルで検索して、関数が正常に機能していることを確認できます。

**注記**  
Lambda@Edge 関数を変更していない場合でも、Lambda 関数の実行環境を更新すると、この関数に影響を与え、実行エラーが発生する可能性があります。テストおよび新しいバージョンへの移行の詳細については、「[Upcoming updates to the AWS Lambda and AWS Lambda@Edge execution environment](https://aws.amazon.com/blogs/compute/upcoming-updates-to-the-aws-lambda-execution-environment/)」を参照してください。

## Lambda@Edge リージョンを判断する
<a name="lambda-edge-testing-debugging-determine-region"></a>

Lambda@Edge 関数がトラフィックを受信しているリージョンを確認するには、 のCloudFront コンソールでその関数のメトリクスを表示しますAWS マネジメントコンソール メトリックスは AWS リージョンごとに表示されます。同じページで、リージョンを選択してそのリージョンのログファイルを表示し、問題を調査することができます。CloudFront が Lambda 関数を実行したときに作成されたログファイルを表示するには、正しい AWS リージョンの CloudWatch ログファイルを確認する必要があります。

CloudFront コンソールの [**Monitoring (モニタリング)**] セクションでのグラフ表示の詳細については、「[Amazon CloudWatch で CloudFront メトリクスをモニタリングする](monitoring-using-cloudwatch.md)」を参照してください。

## アカウントがログを CloudWatch にプッシュするかどうかを判断する
<a name="lambda-edge-testing-debugging-cloudwatch-logs-enabled"></a>

デフォルトでは、CloudFront によって無効な Lambda 関数レスポンスのログ記録が有効になり、[Lambda@Edge 用のサービスにリンクされたロール](lambda-edge-permissions.md#using-service-linked-roles-lambda-edge) のいずれかを使用してログファイルが CloudWatch にプッシュされます。無効な Lambda 関数レスポンスのログ機能がリリースされた前に CloudFront に追加した Lambda@Edge 関数がある場合は、CloudFront トリガーを追加するなど、Lambda@Edge 設定を次に更新するときにログ記録が有効になります。

次を実行して、アカウントでログファイルを CloudWatch にプッシュすることが有効になっているか確認できます。
+ **CloudWatch にログが表示されるかどうかを確認する** – Lambda@Edge 関数が実行されたリージョンを確認します。詳細については、「[Lambda@Edge リージョンを判断する](#lambda-edge-testing-debugging-determine-region)」を参照してください。
+ **関連するサービスリンクロールが IAM のアカウントに存在するかどうかを確認する –** アカウントに IAM ロール `AWSServiceRoleForCloudFrontLogger` が必要です。このロールの詳細については、「[Lambda@Edge 用のサービスにリンクされたロール](lambda-edge-permissions.md#using-service-linked-roles-lambda-edge)」を参照してください。

# Lambda@Edge 関数とレプリカを削除する
<a name="lambda-edge-delete-replicas"></a>

Lambda@Edge 関数を削除できるのは、関数のレプリカが CloudFront によって削除された場合のみです。Lambda 関数のレプリカは、次のような状況では自動的に削除されます。
+ すべての CloudFront ディストリビューションから関数の最後の関連付けを削除した後。複数のディストリビューションで関数が使用されている場合、最後のディストリビューションから関数の関連付けを削除した後にのみ、レプリカが削除されます。
+ 関数が関連付けられた最後のディストリビューションを削除した後。

レプリカは通常、数時間以内に削除されます。Lambda@Edge 関数のレプリカを手動で削除することはできません。これにより、まだ使用中のレプリカが削除され、エラーが発生する状況を防ぐことができます。

**警告**  
CloudFront の外部で Lambda@Edge 関数のレプリカを使用するアプリケーションを構築しないでください。これらのレプリカは、ディストリビューションとの関連付けが削除されるか、ディストリビューション自体が削除されると削除されます。外部のアプリケーションが依存するレプリカが警告なしに削除されて、エラーが発生することがあります。

**CloudFront ディストリビューションから Lambda@Edge 関数の関連付けを削除するには**

1. AWS マネジメントコンソールにサインインし、[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home) で CloudFront コンソールを開きます。

1. 削除する Lambda@Edge 関数の関連付けがあるディストリビューションの ID を選択します。

1. [**Behaviors**] タブを選択します。

1. 削除する Lambda@Edge 関数の関連付けがあるキャッシュ動作を選択し、**[編集]** を選択します。

1. Lambda@Edge 関数の関連付けを削除するには、**[関数の関連付け]**、**[関数タイプ]**、**[関連付けなし]** の順に選択します。

1. **[Save changes]** (変更の保存) をクリックします。

CloudFront ディストリビューションから Lambda@Edge 関数の関連付けを削除した後、必要に応じて から Lambda 関数または関数バージョンを削除することもできますAWS Lambda 関数の関連付けを削除したら、Lambda@Edge 関数のレプリカをクリーンアップできるようになるまで数時間待ちます。その後、Lambda コンソール、AWS CLI、Lambda API、または AWS SDK を使用して関数を削除できます。

特定のバージョンの Lambda 関数が、どの CloudFront ディストリビューションにも関連付けられていない場合は、このバージョンを削除することもできます。**Lambda 関数バージョンのすべての関連付けを削除したら、数時間待ちます。その後、関数バージョンを削除できます。

# Lambda@Edge イベント構造
<a name="lambda-event-structure"></a>

以下のトピックでは、CloudFront がトリガーされたときに Lambda@Edge 関数に渡すリクエストおよびレスポンスイベントオブジェクトについて説明します。

**Topics**
+ [動的オリジン選択](#lambda-event-content-based-routing)
+ [リクエストイベント](#lambda-event-structure-request)
+ [レスポンスイベント](#lambda-event-structure-response)

## 動的オリジン選択
<a name="lambda-event-content-based-routing"></a>

[キャッシュ動作でパスパターン](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern)を使用すると、リクエストされたオブジェクトのパスと名前 (`images/*.jpg` など) に基づいて、リクエストをオリジンにルーティングできます。Lambda@Edge を使用すると、リクエストヘッダーの値など他のプロパティに基づいても、リクエストをオリジンにルーティングできます。

この動的オリジン選択が便利な状況がいくつかあります。たとえば、グローバルな負荷分散に役立つように、地理的に異なるリージョンのオリジンにリクエストを分散させる場合です。あるいは、機能 (ボット処理、SEO 最適化、認証など) が異なるさまざまなオリジンに、リクエストを選択的にルーティングする場合です。この機能の使用方法を示すコードサンプルについては、「[コンテンツベースの動的オリジンの選択 - 例](lambda-examples.md#lambda-examples-content-based-routing-examples)」を参照してください。

CloudFront のオリジンリクエストイベントで、イベント構造の `origin` オブジェクトには、パスパターンに基づいてリクエストがルーティングされるオリジンに関する情報が含まれます。リクエストを別のオリジンにルーティングするように、`origin` オブジェクトの値を更新できます。`origin` オブジェクトを更新するときに、ディストリビューションのオリジンを定義する必要はありません。Amazon S3 オリジンオブジェクトをカスタムオリジンオブジェクトに置き換えたり、その逆にすることもできます。ただし、カスタムオリジンと Amazon S3 オリジンのどちらか (両方は不可) を通じて、リクエストごとに 1 つのオリジンしか指定できません。

## リクエストイベント
<a name="lambda-event-structure-request"></a>

以下のトピックでは、[ビューワーおよびオリジンリクエストイベント](lambda-cloudfront-trigger-events.md)の Lambda 関数に CloudFront が渡すオブジェクトの構造を示します。これらの例は、本文のない `GET` リクエストを示しています。例に続いて、ビューワーとオリジンリクエストイベントで使用可能なすべてのフィールドのリストを示します。

**Topics**
+ [ビューワーリクエストの例](#example-viewer-request)
+ [オリジンリクエストの例](#example-origin-request)
+ [リクエストイベントフィールド](#request-event-fields)

### ビューワーリクエストの例
<a name="example-viewer-request"></a>

次の例は、ビューワーリクエストイベントオブジェクトを示しています。

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "viewer-request",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "host": [
              {
                "key": "Host",
                "value": "d111111abcdef8.cloudfront.net"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "curl/7.66.0"
              }
            ],
            "accept": [
              {
                "key": "accept",
                "value": "*/*"
              }
            ]
          },
          "method": "GET",
          "querystring": "",
          "uri": "/"
        }
      }
    }
  ]
}
```

### オリジンリクエストの例
<a name="example-origin-request"></a>

次の例は、オリジンリクエストイベントオブジェクトを示しています。

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "origin-request",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "x-forwarded-for": [
              {
                "key": "X-Forwarded-For",
                "value": "203.0.113.178"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "Amazon CloudFront"
              }
            ],
            "via": [
              {
                "key": "Via",
                "value": "2.0 2afae0d44e2540f472c0635ab62c232b.cloudfront.net (CloudFront)"
              }
            ],
            "host": [
              {
                "key": "Host",
                "value": "example.org"
              }
            ],
            "cache-control": [
              {
                "key": "Cache-Control",
                "value": "no-cache"
              }
            ]
          },
          "method": "GET",
          "origin": {
            "custom": {
              "customHeaders": {},
              "domainName": "example.org",
              "keepaliveTimeout": 5,
              "path": "",
              "port": 443,
              "protocol": "https",
              "readTimeout": 30,
              "responseCompletionTimeout": 30,
              "sslProtocols": [
                "TLSv1",
                "TLSv1.1",
                "TLSv1.2"
              ]
            }
          },
          "querystring": "",
          "uri": "/"
        }
      }
    }
  ]
}
```

### リクエストイベントフィールド
<a name="request-event-fields"></a>

リクエストイベントオブジェクトデータは、`config` (`Records.cf.config`) と `request` (`Records.cf.request`) の 2 つのサブオブジェクトに含まれています。次のリストは、各サブオブジェクトのフィールドを示しています。

#### 設定オブジェクトのフィールド
<a name="request-event-fields-config"></a>

次のリストでは、`config` オブジェクト (`Records.cf.config`) のフィールドについて説明します。

**`distributionDomainName` (読み取り専用)**  
リクエストに関連付けられているディストリビューションのドメイン名。

**`distributionID` (読み取り専用)**  
リクエストに関連付けられているディストリビューションの ID。

**`eventType` (読み取り専用)**  
リクエストに関連付けられているトリガーのタイプ (`viewer-request` または `origin-request`)。

**`requestId` (読み取り専用)**  
ビューワーから CloudFront へのリクエストを一意に識別する暗号化された文字列。`requestId` の値は CloudFront アクセスログにも `x-edge-request-id` として表示されます。詳細については、「[アクセスログ (標準ログ)](AccessLogs.md)」および「[ログファイルのフィールド](standard-logs-reference.md#BasicDistributionFileFormat)」を参照してください。

#### リクエストオブジェクトのフィールド
<a name="request-event-fields-request"></a>

次のリストでは、`request` オブジェクト (`Records.cf.request`) のフィールドについて説明します。

**`clientIp` (読み取り専用)**  
リクエストを行ったビューワーの IP アドレス。ビューワーが HTTP プロキシまたはロードバランサーを使用してリクエストを送った場合、この値はプロキシまたはロードバランサーの IP アドレスです。

**headers (読み書き)**  
リクエストのヘッダー。次の点に注意してください。  
+ `headers` オブジェクトのキーは標準の HTTP ヘッダー名を小文字にしたものです。小文字のキーを使用して、大文字と小文字を区別せずにヘッダー値にアクセスできます。
+ 各ヘッダーオブジェクト (`headers["accept"]`、`headers["host"]` など) はキーと値のペアの配列です。返されたヘッダーの配列には、リクエストの値ごとに 1 つのキーと値のペアが含まれます。
+ `key` には、HTTP リクエストに表示されるヘッダーの大文字と小文字を区別する名前が含まれます (`Host`、`User-Agent`、`X-Forwarded-For`、`Cookie` など)。
+ `value` には、HTTP リクエストに表示されるヘッダー値が含まれます。
+ Lambda 関数がリクエストヘッダーを追加または変更し、ヘッダー `key` フィールドを含めない場合、Lambda@Edge は指定したヘッダー名を使用してヘッダー `key` を自動的に挿入します。ヘッダー名をどのようにフォーマットしたかにかかわらず、自動的に挿入されるヘッダーキーの各パートは、先頭が大文字になり、ハイフン (-) で区切られます。

  たとえば、ヘッダー `key` なしで次のようなヘッダーを追加できます。

  ```
  "user-agent": [
    {
      "value": "ExampleCustomUserAgent/1.X.0"
    }
  ]
  ```

  この例では、Lambda@Edge は `"key": "User-Agent"` を自動的に挿入します。
ヘッダー使用の制限の詳細については、「[エッジ関数に対する制限](edge-functions-restrictions.md)」を参照してください。

**`method` (読み取り専用)**  
リクエストの HTTP メソッド。

**`querystring` (読み書き)**  
リクエスト内のクエリ文字列 (存在する場合)。リクエストにクエリ文字列が含まれていない場合でも、イベントオブジェクトには `querystring` が含まれ、値が空になります。クエリ文字列の詳細については、「[クエリ文字列パラメータに基づいてコンテンツをキャッシュする](QueryStringParameters.md)」を参照してください。

**`uri` (読み書き)**  
リクエストされたオブジェクトの相対パス。Lambda 関数が `uri` 値を変更する場合、次の点に注意してください。  
+ 新しい `uri` 値は、スラッシュ (/) で始める必要があります。
+ 関数で `uri` 値を変更すると、ビューワーがリクエストしているオブジェクトが変更されます。
+ 関数で `uri` 値を変更しても、リクエストのキャッシュ動作や送信先オリジンは*変わりません*。

**`body` (読み書き)**  
HTTP リクエストの本文。`body` 構造には、次のフィールドを含めることができます。    
**`inputTruncated` (読み取り専用)**  
本文が Lambda@Edge で切り捨てられたかどうかを示すブーリアン型フラグ。詳細については、「[[本文を含める] オプションを使用する場合のリクエスト本文に対する制限](lambda-at-edge-function-restrictions.md#lambda-at-edge-restrictions-request-body)」を参照してください。  
**`action` (読み書き)**  
本文で実行する予定のアクション。`action` のオプションは次のとおりです。  
+ `read-only:` これがデフォルト値です。Lambda 関数からレスポンスを返す際に、`action` が読み取り専用の場合、Lambda@Edge は `encoding` または `data` への変更をすべて無視します。
+ `replace:` オリジンに送信される本文を置き換えるときに指定します。  
**`encoding` (読み書き)**  
本文のエンコード。Lambda@Edge が Lambda 関数に本文を公開すると、まず本文を base64-encoding に変換します。本文を置き換える `replace` として `action` を選択した場合、`base64` (デフォルト) または `text` エンコードを使用することもできます。`encoding` を `base64` と指定したが本文が有効な base64 でない場合、CloudFront はエラーを返します。  
**`data` (読み書き)**  
リクエストボディのコンテンツ。

**`origin` (読み書き) (オリジンイベントのみ)**  
リクエストの送信先のオリジン。`origin` 構造には、*オリジンを 1 つだけ*含める必要があります。カスタムオリジンでも Amazon S3 オリジンでも構いません。  
指定するオリジンタイプ (カスタムオリジンまたは Amazon S3 オリジン) に応じて、以下のフィールドをリクエストに指定する必要があります。    
**`customHeaders` (読み取り/書き込み) (カスタムおよび Amazon S3 オリジン)**  
(オプション) 各カスタムヘッダーの名前と値のペアを指定することで、カスタムヘッダーをリクエストに含めることができます。許可されていないヘッダーを追加することはできず、同じ名前のヘッダーを `Records.cf.request.headers` に含めることもできません。[リクエストヘッダーに関する注意事項](#request-event-fields-request-headers)は、カスタムヘッダーにも適用されます。詳細については、「[CloudFront でオリジンリクエストに追加できないカスタムヘッダー](add-origin-custom-headers.md#add-origin-custom-headers-denylist)」および「[エッジ関数に対する制限](edge-functions-restrictions.md)」を参照してください。  
**`domainName` (読み取り/書き込み) (カスタムおよび Amazon S3 オリジン)**  
オリジンのドメイン名。ドメイン名を空にすることはできません。  
+ **カスタムオリジンの場合** – DNS ドメイン名を指定します (`www.example.com` など)。ドメイン名にコロン (:) を含めることはできません。また、IP アドレスにすることはできません。ドメイン名の最大長は 253 文字です。
+ **Amazon S3 オリジンの場合** - Amazon S3 バケットの DNS ドメイン名を指定します (`amzn-s3-demo-bucket.s3.eu-west-1.amazonaws.com` など)。この名前は最大 128 文字で、すべて小文字であることが必要です。  
**`path` (読み取り/書き込み) (カスタムおよび Amazon S3 オリジン)**  
リクエストがコンテンツを検索するサーバーのディレクトリパス。パスは、先頭をスラッシュ (/) にする必要があります。末尾をスラッシュ (/) にすることはできません (例えば、末尾が `example-path/` は不可です)。カスタムオリジンの場合のみ、パスは URL エンコードされ、最大長は 255 文字にする必要があります。  
**`keepaliveTimeout` (読み書き) (カスタムオリジンのみ)**  
CloudFront がレスポンスの最後のパケットを受け取ってからオリジンへの接続を維持しようとする期間 (秒)。この値には、1～120 の範囲の数値を指定する必要があります。  
**`port` (読み書き) (カスタムオリジンのみ)**  
カスタムオリジンでの CloudFront の接続先ポート。ポートは 80 または 443 であるか、1024 〜 65535 の範囲の数値であることが必要です。  
**`protocol` (読み書き) (カスタムオリジンのみ)**  
オリジンに接続するとき CloudFront が使用する接続プロトコル。ここには、`http` または `https` が表示されます。  
**`readTimeout` (読み取り/書き込み) (カスタムおよび Amazon S3 オリジン)**  
オリジンにリクエストを送信した後、CloudFront がレスポンスを待機する時間 (秒単位)。これは、レスポンスのパケットを受信してから次のパケットを受信するまで CloudFront が待機する時間も指定します。この値には、1～120 の範囲の数値を指定する必要があります。  
高いクォータが必要な場合は、「[オリジン別の応答タイムアウト](cloudfront-limits.md#limits-web-distributions)」を参照してください。  
**`responseCompletionTimeout` (読み取り/書き込み) (カスタムおよび Amazon S3 オリジン)**  
CloudFront からオリジンへのリクエストを開いたままにして応答を待機できる時間 (秒単位)。この時間までにオリジンから完全な応答が受信されない場合、CloudFront は接続を終了します。  
`responseCompletionTimeout` の値は、`readTimeout` の値以上にする必要があります。この値を 0 に設定すると、設定した以前の値はすべて削除され、デフォルトに戻ります。また、イベントリクエストから `responseCompletionTimeout` フィールドを削除することでもこれを実現できます。  
**`sslProtocols` (読み書き) (カスタムオリジンのみ)**  
オリジンとの HTTPS 接続を確立するときに CloudFront が使用できる最小限の SSL/TLS プロトコル。値は、`TLSv1.2`、`TLSv1.1`、`TLSv1`、または `SSLv3` のいずれかです。  
**`authMethod` (読み取り/書き込み) (Amazon S3 オリジンのみ)**  
[オリジンアクセスアイデンティティ (OAI)](private-content-restricting-access-to-s3.md#private-content-restricting-access-to-s3-oai) を使用している場合は、このフィールドを `origin-access-identity` に設定します。OAI を使用していない場合は、`none` に設定します。`authMethod` を `origin-access-identity` に設定した場合、いくつかの要件があります。  
+ `region` を指定する必要があります (次のフィールドを参照)。
+ リクエストをある Amazon S3 オリジンから別のオリジンに変更する場合は、同じ OAI を使用する必要があります。
+ リクエストをカスタムオリジンから Amazon S3 オリジンに変更する場合、OAI を使用することはできません。
このフィールドは[オリジンアクセスコントロール (OAC) ](private-content-restricting-access-to-s3.md)をサポートしていません。  
**`region` (読み取り/書き込み) (Amazon S3 オリジンのみ)**  
Amazon S3 バケットの AWS リージョン。これは、`authMethod` を `origin-access-identity` に設定した場合にのみ必要です。

## レスポンスイベント
<a name="lambda-event-structure-response"></a>

以下のトピックでは、[ビューワーおよびオリジンレスポンスイベント](lambda-cloudfront-trigger-events.md)の Lambda 関数に CloudFront が渡すオブジェクトの構造を示します。例に続いて、ビューワーとオリジンレスポンスイベントで使用可能なすべてのフィールドのリストを示します。

**Topics**
+ [オリジンレスポンスの例](#lambda-event-structure-response-origin)
+ [ビューワーレスポンスの例](#lambda-event-structure-response-viewer)
+ [レスポンスイベントのフィールド](#response-event-fields)

### オリジンレスポンスの例
<a name="lambda-event-structure-response-origin"></a>

次の例は、オリジンレスポンスイベントオブジェクトを示しています。

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "origin-response",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "x-forwarded-for": [
              {
                "key": "X-Forwarded-For",
                "value": "203.0.113.178"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "Amazon CloudFront"
              }
            ],
            "via": [
              {
                "key": "Via",
                "value": "2.0 8f22423015641505b8c857a37450d6c0.cloudfront.net (CloudFront)"
              }
            ],
            "host": [
              {
                "key": "Host",
                "value": "example.org"
              }
            ],
            "cache-control": [
              {
                "key": "Cache-Control",
                "value": "no-cache"
              }
            ]
          },
          "method": "GET",
          "origin": {
            "custom": {
              "customHeaders": {},
              "domainName": "example.org",
              "keepaliveTimeout": 5,
              "path": "",
              "port": 443,
              "protocol": "https",
              "readTimeout": 30,
              "responseCompletionTimeout": 30,
              "sslProtocols": [
                "TLSv1",
                "TLSv1.1",
                "TLSv1.2"
              ]
            }
          },
          "querystring": "",
          "uri": "/"
        },
        "response": {
          "headers": {
            "access-control-allow-credentials": [
              {
                "key": "Access-Control-Allow-Credentials",
                "value": "true"
              }
            ],
            "access-control-allow-origin": [
              {
                "key": "Access-Control-Allow-Origin",
                "value": "*"
              }
            ],
            "date": [
              {
                "key": "Date",
                "value": "Mon, 13 Jan 2020 20:12:38 GMT"
              }
            ],
            "referrer-policy": [
              {
                "key": "Referrer-Policy",
                "value": "no-referrer-when-downgrade"
              }
            ],
            "server": [
              {
                "key": "Server",
                "value": "ExampleCustomOriginServer"
              }
            ],
            "x-content-type-options": [
              {
                "key": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ],
            "x-frame-options": [
              {
                "key": "X-Frame-Options",
                "value": "DENY"
              }
            ],
            "x-xss-protection": [
              {
                "key": "X-XSS-Protection",
                "value": "1; mode=block"
              }
            ],
            "content-type": [
              {
                "key": "Content-Type",
                "value": "text/html; charset=utf-8"
              }
            ],
            "content-length": [
              {
                "key": "Content-Length",
                "value": "9593"
              }
            ]
          },
          "status": "200",
          "statusDescription": "OK"
        }
      }
    }
  ]
}
```

### ビューワーレスポンスの例
<a name="lambda-event-structure-response-viewer"></a>

次の例は、ビューワーレスポンスイベントオブジェクトを示しています。

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "viewer-response",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "host": [
              {
                "key": "Host",
                "value": "d111111abcdef8.cloudfront.net"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "curl/7.66.0"
              }
            ],
            "accept": [
              {
                "key": "accept",
                "value": "*/*"
              }
            ]
          },
          "method": "GET",
          "querystring": "",
          "uri": "/"
        },
        "response": {
          "headers": {
            "access-control-allow-credentials": [
              {
                "key": "Access-Control-Allow-Credentials",
                "value": "true"
              }
            ],
            "access-control-allow-origin": [
              {
                "key": "Access-Control-Allow-Origin",
                "value": "*"
              }
            ],
            "date": [
              {
                "key": "Date",
                "value": "Mon, 13 Jan 2020 20:14:56 GMT"
              }
            ],
            "referrer-policy": [
              {
                "key": "Referrer-Policy",
                "value": "no-referrer-when-downgrade"
              }
            ],
            "server": [
              {
                "key": "Server",
                "value": "ExampleCustomOriginServer"
              }
            ],
            "x-content-type-options": [
              {
                "key": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ],
            "x-frame-options": [
              {
                "key": "X-Frame-Options",
                "value": "DENY"
              }
            ],
            "x-xss-protection": [
              {
                "key": "X-XSS-Protection",
                "value": "1; mode=block"
              }
            ],
            "age": [
              {
                "key": "Age",
                "value": "2402"
              }
            ],
            "content-type": [
              {
                "key": "Content-Type",
                "value": "text/html; charset=utf-8"
              }
            ],
            "content-length": [
              {
                "key": "Content-Length",
                "value": "9593"
              }
            ]
          },
          "status": "200",
          "statusDescription": "OK"
        }
      }
    }
  ]
}
```

### レスポンスイベントのフィールド
<a name="response-event-fields"></a>

レスポンスイベントオブジェクトデータは、`config` (`Records.cf.config`)、`request` (`Records.cf.request`)、`response` (`Records.cf.response`) の 3 つのサブオブジェクトに含まれています。リクエストオブジェクトのフィールドの詳細については、「[リクエストオブジェクトのフィールド](#request-event-fields-request)」を参照してください。次のリストでは、`config` および `response` サブオブジェクトのフィールドについて説明します。

#### 設定オブジェクトのフィールド
<a name="response-event-fields-config"></a>

次のリストでは、`config` オブジェクト (`Records.cf.config`) のフィールドについて説明します。

**`distributionDomainName` (読み取り専用)**  
レスポンスに関連付けられているディストリビューションのドメイン名。

**`distributionID` (読み取り専用)**  
レスポンスに関連付けられているディストリビューションの ID。

**`eventType` (読み取り専用)**  
レスポンスに関連付けられているトリガーのタイプ (`origin-response` または `viewer-response`)。

**`requestId` (読み取り専用)**  
このレスポンスが関連付けられているビューワーから CloudFront へのリクエストを一意に識別する暗号化された文字列。`requestId` の値は CloudFront アクセスログにも `x-edge-request-id` として表示されます。詳細については、「[アクセスログ (標準ログ)](AccessLogs.md)」および「[ログファイルのフィールド](standard-logs-reference.md#BasicDistributionFileFormat)」を参照してください。

#### レスポンスオブジェクトのフィールド
<a name="response-event-fields-response"></a>

次のリストでは、`response` オブジェクト (`Records.cf.response`) のフィールドについて説明します。Lambda@Edge 関数を使用して HTTP レスポンスを生成する方法については、「[リクエストトリガーでの HTTP レスポンスを生成する](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests)」を参照してください。

**`headers` (読み書き)**  
レスポンスのヘッダー。次の点に注意してください。  
+ `headers` オブジェクトのキーは標準の HTTP ヘッダー名を小文字にしたものです。小文字のキーを使用して、大文字と小文字を区別せずにヘッダー値にアクセスできます。
+ 各ヘッダーオブジェクト (`headers["content-type"]`、`headers["content-length"]` など) はキーと値のペアの配列です。返されたヘッダーの配列には、レスポンスの値ごとに 1 つのキーと値のペアが含まれます。
+ `key` には、HTTP レスポンスに表示される際に大文字と小文字が区別されるヘッダー名が含まれます (`Content-Type`、`Content-Length`、`Cookie` など)。
+ `value` には、HTTP レスポンスに表示されるヘッダー値が含まれます。
+ Lambda 関数がレスポンスヘッダーを追加または変更し、ヘッダー `key` フィールドを含めない場合、Lambda@Edge は指定したヘッダー名を使用してヘッダー `key` を自動的に挿入します。ヘッダー名をどのようにフォーマットしたかにかかわらず、自動的に挿入されるヘッダーキーの各パートは、先頭が大文字になり、ハイフン (-) で区切られます。

  たとえば、ヘッダー `key` なしで次のようなヘッダーを追加できます。

  ```
  "content-type": [
    {
      "value": "text/html;charset=UTF-8"
    }
  ]
  ```

  この例では、Lambda@Edge は `"key": "Content-Type"` を自動的に挿入します。
ヘッダー使用の制限の詳細については、「[エッジ関数に対する制限](edge-functions-restrictions.md)」を参照してください。

**`status`**  
レスポンスの HTTP ステータスコード。

**`statusDescription`**  
レスポンスの HTTP ステータスの説明。

# リクエストとレスポンスを使用する
<a name="lambda-generating-http-responses"></a>

Lambda@Edge のリクエストとレスポンスを使用するには、以下のトピックを参照してください。

**Topics**
+ [オリジンフェイルオーバーで Lambda@Edge 関数を使用する](#lambda-and-origin-failover)
+ [リクエストトリガーでの HTTP レスポンスを生成する](#lambda-generating-http-responses-in-requests)
+ [オリジンレスポンストリガーでの HTTP レスポンスを更新する](#lambda-updating-http-responses)
+ [include body オプションを選択してリクエストボディにアクセスする](#lambda-include-body-access)

## オリジンフェイルオーバーで Lambda@Edge 関数を使用する
<a name="lambda-and-origin-failover"></a>

例えば、高い可用性を確保するために設定したオリジンフェイルオーバーなど、オリジングループで設定した CloudFront ディストリビューションで Lambda@Edge 関数を使用できます。オリジングループで Lambda 関数を使用するには、キャッシュ動作を作成するときにオリジングループのオリジンリクエストまたはオリジンレスポンストリガーで関数を指定します。

詳細については次を参照してください:
+ **オリジングループを作成する:** [オリジングループを作成する](high_availability_origin_failover.md#concept_origin_groups.creating)
+ **Lambda@Edge でのオリジンフェイルオーバーの機能 **[Lambda@Edge 関数でのオリジンフェイルオーバーの使用](high_availability_origin_failover.md#concept_origin_groups.lambda)

## リクエストトリガーでの HTTP レスポンスを生成する
<a name="lambda-generating-http-responses-in-requests"></a>

CloudFront がリクエストを受け取ったときに、Lambda 関数が HTTP レスポンスを生成することで、CloudFront がレスポンスをオリジンに転送せずに直接ビューワーに返すようにできます。HTTP レスポンスを生成することで、オリジンの負荷が軽減され、通常はビューワーのレイテンシーも短縮されます。

以下に示しているのは、HTTP レスポンスを生成する一般的なシナリオです。
+ 小さいウェブページをビューワーに返す。
+ HTTP 301 または 302 ステータスコードを返して、ユーザーを別のウェブページにリダイレクトする。
+ ユーザーが認証されない場合に HTTP 401 ステータスコードをビューワーに返す。

Lambda@Edge 関数は、以下の CloudFront イベントが発生したときに HTTP レスポンスを生成できます。

**ビューワーリクエストイベント**  
関数がビューワーリクエストイベントによってトリガーされると、CloudFront はレスポンスをビューワーに返し、キャッシュしません。

**オリジンリクエストイベント**  
関数がオリジンリクエストイベントによってトリガーされると、CloudFront は、その関数によって以前に生成されたレスポンスがエッジキャッシュ内にあるかどうかを確認します。  
+ レスポンスがキャッシュ内にある場合、関数は実行されず、CloudFront はキャッシュされたレスポンスをビューワーに返します。
+ レスポンスがキャッシュ内にない場合、関数が実行され、CloudFront はそのレスポンスをビューワーに返すとともに、キャッシュします。

HTTP レスポンスを生成するためのサンプルコードを見るには、「[Lambda@Edge 関数の例](lambda-examples.md)」を参照してください。レスポンストリガーの HTTP レスポンスを置き換えることもできます。詳細については、「[オリジンレスポンストリガーでの HTTP レスポンスを更新する](#lambda-updating-http-responses)」を参照してください。

### プログラミングモデル
<a name="lambda-generating-http-responses-programming-model"></a>

このセクションでは、Lambda@Edge を使用して HTTP レスポンスを生成するためのプログラミングモデルについて説明します。

**Topics**
+ [レスポンスオブジェクト](#lambda-generating-http-responses-object)
+ [エラー](#lambda-generating-http-responses-errors)
+ [必須フィールド](#lambda-generating-http-responses-required-fields)

#### レスポンスオブジェクト
<a name="lambda-generating-http-responses-object"></a>

`result` メソッドの `callback` パラメータとして返すレスポンスには、以下の構造が必要です (`status` フィールドのみが必須)。

```
const response = {
    body: 'content',
    bodyEncoding: 'text' | 'base64',
    headers: {
        'header name in lowercase': [{
            key: 'header name in standard case',
            value: 'header value'
         }],
         ...
    },
    status: 'HTTP status code (string)',
    statusDescription: 'status description'
};
```

レスポンスオブジェクトには、以下の値が含まれる場合があります。

**`body`**  
生成されたレスポンスで CloudFront が返す本文 (存在する場合)。

**`bodyEncoding`**  
`body` で指定した値のエンコード。有効なエンコードは `text` と `base64` のみです。`body` オブジェクトに `response` を含めるが、`bodyEncoding` を省略した場合、CloudFront は本文をテキストとして扱います。  
`bodyEncoding` を `base64` と指定したが本文が有効な base64 でない場合、CloudFront はエラーを返します。

**`headers`**  
生成されるレスポンスで CloudFront が返すヘッダー。次の点に注意してください。  
+ `headers` オブジェクトのキーは標準の HTTP ヘッダー名を小文字にしたものです。小文字のキーを使用して、大文字と小文字を区別せずにヘッダー値にアクセスできます。
+ 各ヘッダー (`headers["accept"]`、`headers["host"]` など) はキーと値のペアの配列です。返されたヘッダーの配列には、生成されたレスポンスの値ごとに 1 つのキーと値のペアが含まれます。
+ `key` (省略可能) は、HTTP リクエストに表示されるヘッダーの大文字と小文字を区別する名前です (`accept`、`host` など)。
+ ヘッダー値として `value` を指定します。
+ キーと値のペアのヘッダーキー部分を含めない場合、Lambda@Edge は指定したヘッダー名を使用してヘッダーキーを自動的に挿入します。ヘッダー名をどのようにフォーマットしたかにかかわらず、挿入されるヘッダーキーは、各パートの先頭の大文字がハイフン (-) で区切られて自動的にフォーマットされます。

  たとえば、ヘッダーキー `'content-type': [{ value: 'text/html;charset=UTF-8' }]` なしで次のようなヘッダーを追加できます。

  この例で、Lambda@Edge はヘッダーキー `Content-Type` を作成します。
ヘッダー使用の制限の詳細については、「[エッジ関数に対する制限](edge-functions-restrictions.md)」を参照してください。

**`status`**  
HTTP ステータスコード ステータスコードを文字列として指定します。CloudFront は、提供されているステータスコードを、以下に使用します。  
+ レスポンスでの返却
+ オリジンリクエストイベントによってトリガーされた関数によってレスポンスが生成されたときの、CloudFront エッジキャッシュへの保存
+ CloudFront へのログイン [アクセスログ (標準ログ)](AccessLogs.md)
`status` の値が 200～599 の範囲にない場合、CloudFront はエラーをビューワーに返します。

**`statusDescription`**  
CloudFront がレスポンスで HTTP ステータスコードに付けて返す説明。標準の説明 (HTTP ステータスコード 200 の場合の `OK` など) を使用する必要はありません。

#### エラー
<a name="lambda-generating-http-responses-errors"></a>

生成された HTTP レスポンスで発生する可能性があるエラーを以下に示します。

**レスポンスに本文が含まれ、ステータスに 204 (No Content) が指定されている**  
関数がビューワーリクエストによってトリガーされると、CloudFront は、以下の両方が当てはまる場合に、HTTP 502 ステータスコード (Bad Gateway) をビューワーに返します。  
+ `status` の値が 204 (No Content) である。
+ このレスポンスに `body` の値が含まれている。
これは、`HTTP 204` レスポンスにはメッセージ本文を含める必要がないことを述べている RFC 2616 のオプションの制限を Lambda@Edge が適用しているためです。

**生成されるレスポンスのサイズ制限を超えている**  
Lambda 関数によって生成されるレスポンスの最大サイズは、関数をトリガーするイベントによって異なります。  
+ **ビューワーリクエストイベント** - 40 KB
+ **オリジンリクエストイベント** - 1 MB
レスポンスがこの許容サイズを超えると、CloudFront が HTTP 502 ステータスコード (Bad Gateway) をビューワーに返します。

#### 必須フィールド
<a name="lambda-generating-http-responses-required-fields"></a>

`status` フィールドは必須です。

その他のすべてのフィールドはオプションです。

## オリジンレスポンストリガーでの HTTP レスポンスを更新する
<a name="lambda-updating-http-responses"></a>

CloudFront がオリジンサーバーから HTTP レスポンスを受け取ったときに、キャッシュ動作に関連付けられた origin-response トリガーがあれば、HTTP レスポンスを変更して、オリジンから返されたものを上書きできます。

以下に示しているのは、HTTP レスポンスを更新する一般的なシナリオです。
+ オリジンがエラーステータスコード (4xx または 5xx) を返すと、ステータスを変更して HTTP 200 ステータスコードを設定し、ビューワーに返す静的な本文コンテンツを作成する。サンプルコードについては、「[例: オリジンレスポンストリガーを使用してエラーステータスコードを 200 に更新する](lambda-examples.md#lambda-examples-custom-error-static-body)」を参照してください。
+ オリジンがエラーステータスコード (4xx または 5xx) を返すと、ステータスを変更して HTTP 301 または HTTP 302 ステータスコードを設定し、ユーザーを別のウェブサイトにリダイレクトする。サンプルコードについては、「[例: オリジンレスポンストリガーを使用してエラーステータスコードを 302 に更新する](lambda-examples.md#lambda-examples-custom-error-new-site)」を参照してください。

**注記**  
関数は `200` と `599` の間 (両端を含む) のステータス値を返す必要があります。そうでない場合、CloudFront はエラーをビューワーに返します。

ビューワーとオリジンのリクエストイベントの HTTP レスポンスを置き換えることもできます。詳細については、「[リクエストトリガーでの HTTP レスポンスを生成する](#lambda-generating-http-responses-in-requests)」を参照してください。

HTTP レスポンスを使用する場合、Lambda@Edge は、オリジンサーバーから返された本文を origin-response トリガーに公開しません。必要な値に設定することで静的なコンテンツ本文を生成したり、値を空に設定することで関数内の本文を削除したりできます。関数内の本文フィールドを更新しない場合は、オリジンサーバーによって返された元の本文がビューワーに返されます。

## include body オプションを選択してリクエストボディにアクセスする
<a name="lambda-include-body-access"></a>

書き込み可能な HTTP メソッド (POST、PUT、DELETE など) のリクエストのボディを Lambda@Edge で公開することを選択できるため、Lambda 関数でそのボディにアクセスできます。読み取り専用アクセスを選択することも、ボディを置き換えることを指定することもできます。

このオプションを有効にするには、ビューワーリクエストやオリジンリクエストイベントのために関数に CloudFront トリガーを作成するとき、[**ボディを含める**] を選択します。詳細については、「[Lambda@Edge 関数のトリガーを追加する](lambda-edge-add-triggers.md)」を参照してください。または、関数で [**ボディを含める**] を使用する方法については、「[Lambda@Edge イベント構造](lambda-event-structure.md)」を参照してください。

この機能を使用する場合のシナリオには次のようなものがあります。
+ お客様の入力データをオリジンサーバーに返送することなく、「お問い合わせ」フォームのようなウェブフォームを処理します。
+ ビューワーブラウザによって送信されるウェブビーコンデータを収集し、エッジで処理します。

サンプルコードについては、「[Lambda@Edge 関数の例](lambda-examples.md)」を参照してください。

**注記**  
リクエストボディが大きい場合は、Lambda@Edge によって切り捨てられます。最大サイズ制限と切り捨ての詳細については、「[[本文を含める] オプションを使用する場合のリクエスト本文に対する制限](lambda-at-edge-function-restrictions.md#lambda-at-edge-restrictions-request-body)」を参照してください。

# Lambda@Edge 関数の例
<a name="lambda-examples"></a>

Amazon CloudFront で Lambda 関数を使用するには、以下の例を参照してください。

**注記**  
Lambda@Edge 関数にランタイム Node.js 18 以降を選択すると、`index.mjs` ファイルが自動的に作成されます。次のコード例を使用するには、`index.mjs` ファイルの名前を `index.js` に変更します。

**Topics**
+ [一般的な例](#lambda-examples-general-examples)
+ [レスポンスを生成する - 例](#lambda-examples-generated-response-examples)
+ [クエリ文字列 - 例](#lambda-examples-query-string-examples)
+ [国またはデバイスタイプヘッダー別のコンテンツのパーソナライズ - 例](#lambda-examples-redirecting-examples)
+ [コンテンツベースの動的オリジンの選択 - 例](#lambda-examples-content-based-routing-examples)
+ [エラーステータスを更新する - 例](#lambda-examples-update-error-status-examples)
+ [リクエストボディにアクセスする - 例](#lambda-examples-access-request-body-examples)

## 一般的な例
<a name="lambda-examples-general-examples"></a>

以下の例は、CloudFront で Lambda@Edge を使用する一般的な方法を示しています。

**Topics**
+ [例: A/B テスト](#lambda-examples-a-b-testing)
+ [例: レスポンスヘッダーをオーバーライドする](#lambda-examples-overriding-response-header)

### 例: A/B テスト
<a name="lambda-examples-a-b-testing"></a>

次の例を使用すると、リダイレクトを作成したり URL を変更したりすることなく、2 つの異なるバージョンのイメージをテストできます。この例では、ビューワーリクエスト内の Cookie を読み取り、それに応じてリクエスト URL を変更します。ビューワーがいずれかの期待値を使用して Cookie を送信しない場合、例ではビューワーを URL のいずれかにランダムに割り当てます。

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    if (request.uri !== '/experiment-pixel.jpg') {
        // do not process if this is not an A-B test request
        callback(null, request);
        return;
    }

    const cookieExperimentA = 'X-Experiment-Name=A';
    const cookieExperimentB = 'X-Experiment-Name=B';
    const pathExperimentA = '/experiment-group/control-pixel.jpg';
    const pathExperimentB = '/experiment-group/treatment-pixel.jpg';

    /*
     * Lambda at the Edge headers are array objects.
     *
     * Client may send multiple Cookie headers, i.e.:
     * > GET /viewerRes/test HTTP/1.1
     * > User-Agent: curl/7.18.1 (x86_64-unknown-linux-gnu) libcurl/7.18.1 OpenSSL/1.0.1u zlib/1.2.3
     * > Cookie: First=1; Second=2
     * > Cookie: ClientCode=abc
     * > Host: example.com
     *
     * You can access the first Cookie header at headers["cookie"][0].value
     * and the second at headers["cookie"][1].value.
     *
     * Header values are not parsed. In the example above,
     * headers["cookie"][0].value is equal to "First=1; Second=2"
     */
    let experimentUri;
    if (headers.cookie) {
        for (let i = 0; i < headers.cookie.length; i++) {
            if (headers.cookie[i].value.indexOf(cookieExperimentA) >= 0) {
                console.log('Experiment A cookie found');
                experimentUri = pathExperimentA;
                break;
            } else if (headers.cookie[i].value.indexOf(cookieExperimentB) >= 0) {
                console.log('Experiment B cookie found');
                experimentUri = pathExperimentB;
                break;
            }
        }
    }

    if (!experimentUri) {
        console.log('Experiment cookie has not been found. Throwing dice...');
        if (Math.random() < 0.75) {
            experimentUri = pathExperimentA;
        } else {
            experimentUri = pathExperimentB;
        }
    }

    request.uri = experimentUri;
    console.log(`Request uri set to "${request.uri}"`);
    callback(null, request);
};
```

------
#### [ Python ]

```
import json
import random

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    if request['uri'] != '/experiment-pixel.jpg':
        # Not an A/B Test
        return request

    cookieExperimentA, cookieExperimentB = 'X-Experiment-Name=A', 'X-Experiment-Name=B'
    pathExperimentA, pathExperimentB = '/experiment-group/control-pixel.jpg', '/experiment-group/treatment-pixel.jpg'

    '''
    Lambda at the Edge headers are array objects.

    Client may send multiple cookie headers. For example:
    > GET /viewerRes/test HTTP/1.1
    > User-Agent: curl/7.18.1 (x86_64-unknown-linux-gnu) libcurl/7.18.1 OpenSSL/1.0.1u zlib/1.2.3
    > Cookie: First=1; Second=2
    > Cookie: ClientCode=abc
    > Host: example.com

    You can access the first Cookie header at headers["cookie"][0].value
    and the second at headers["cookie"][1].value.

    Header values are not parsed. In the example above,
    headers["cookie"][0].value is equal to "First=1; Second=2"
    '''

    experimentUri = ""

    for cookie in headers.get('cookie', []):
        if cookieExperimentA in cookie['value']:
            print("Experiment A cookie found")
            experimentUri = pathExperimentA
            break
        elif cookieExperimentB in cookie['value']:
            print("Experiment B cookie found")
            experimentUri = pathExperimentB
            break

    if not experimentUri:
        print("Experiment cookie has not been found. Throwing dice...")
        if random.random() < 0.75:
            experimentUri = pathExperimentA
        else:
            experimentUri = pathExperimentB

    request['uri'] = experimentUri
    print(f"Request uri set to {experimentUri}")
    return request
```

------

### 例: レスポンスヘッダーをオーバーライドする
<a name="lambda-examples-overriding-response-header"></a>

以下の例は、レスポンスヘッダーの値を別のヘッダーの値に基づいて変更する方法を示しています。

------
#### [ Node.js ]

```
export const handler = async (event) => {
    const response = event.Records[0].cf.response;
    const headers = response.headers;

    const headerNameSrc = 'X-Amz-Meta-Last-Modified';
    const headerNameDst = 'Last-Modified';

    if (headers[headerNameSrc.toLowerCase()]) {
        headers[headerNameDst.toLowerCase()] = [{
            key: headerNameDst,
            value: headers[headerNameSrc.toLowerCase()][0].value,
        }];
        console.log(`Response header "${headerNameDst}" was set to ` +
                    `"${headers[headerNameDst.toLowerCase()][0].value}"`);
    }

    return response;
};
```

------
#### [ Python ]

```
import json 

def lambda_handler(event, context):
    response = event['Records'][0]['cf']['response']
    headers = response['headers']
    
    header_name_src = 'X-Amz-Meta-Last-Modified'
    header_name_dst = 'Last-Modified'
    
    if headers.get(header_name_src.lower()):
        headers[header_name_dst.lower()] = [{
            'key': header_name_dst,
            'value': headers[header_name_src.lower()][0]['value']
        }]
        print(f'Response header "{header_name_dst}" was set to '
              f'"{headers[header_name_dst.lower()][0]["value"]}"')
    
    return response
```

------

## レスポンスを生成する - 例
<a name="lambda-examples-generated-response-examples"></a>

以下の例は、Lambda@Edge を使用してレスポンスを生成する方法を示しています。

**Topics**
+ [例: 静的コンテンツを提供する (生成されたレスポンス)](#lambda-examples-static-web-server)
+ [例: HTTP リダイレクトを生成する (生成されたレスポンス)](#lambda-examples-http-redirect)

### 例: 静的コンテンツを提供する (生成されたレスポンス)
<a name="lambda-examples-static-web-server"></a>

次の例は、Lambda 関数を使用して静的ウェブサイトコンテンツを提供する方法を示しています。これにより、オリジンサーバーの負荷と全体的なレイテンシーが軽減されます。

**注記**  
HTTP レスポンスは、ビューワーリクエストおよびオリジンリクエストのイベントに対して生成できます。詳細については、「[リクエストトリガーでの HTTP レスポンスを生成する](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests)」を参照してください。  
オリジンレスポンスイベントで HTTP レスポンスのボディを置き換えたり、削除することもできます。詳細については、「[オリジンレスポンストリガーでの HTTP レスポンスを更新する](lambda-generating-http-responses.md#lambda-updating-http-responses)」を参照してください。

------
#### [ Node.js ]

```
'use strict';

const content = `
<\!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Simple Lambda@Edge Static Content Response</title>
  </head>
  <body>
    <p>Hello from Lambda@Edge!</p>
  </body>
</html>
`;

exports.handler = (event, context, callback) => {
    /*
     * Generate HTTP OK response using 200 status code with HTML body.
     */
    const response = {
        status: '200',
        statusDescription: 'OK',
        headers: {
            'cache-control': [{
                key: 'Cache-Control',
                value: 'max-age=100'
            }],
            'content-type': [{
                key: 'Content-Type',
                value: 'text/html'
            }]
        },
        body: content,
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
import json

CONTENT = """
<\!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Simple Lambda@Edge Static Content Response</title>
</head>
<body>
    <p>Hello from Lambda@Edge!</p>
</body>
</html>
"""

def lambda_handler(event, context):
    # Generate HTTP OK response using 200 status code with HTML body.
    response = {
        'status': '200',
        'statusDescription': 'OK',
        'headers': {
            'cache-control': [
                {
                    'key': 'Cache-Control',
                    'value': 'max-age=100'
                }
            ],
            "content-type": [
                {
                    'key': 'Content-Type',
                    'value': 'text/html'
                }
            ]
        },
        'body': CONTENT
    }
    return response
```

------

### 例: HTTP リダイレクトを生成する (生成されたレスポンス)
<a name="lambda-examples-http-redirect"></a>

次の例は、HTTP リダイレクトを生成する方法を示しています。

**注記**  
HTTP レスポンスは、ビューワーリクエストおよびオリジンリクエストのイベントに対して生成できます。詳細については、「[リクエストトリガーでの HTTP レスポンスを生成する](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests)」を参照してください。

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    /*
     * Generate HTTP redirect response with 302 status code and Location header.
     */
    const response = {
        status: '302',
        statusDescription: 'Found',
        headers: {
            location: [{
                key: 'Location',
                value: 'https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html',
            }],
        },
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):

    # Generate HTTP redirect response with 302 status code and Location header.

    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': 'https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html'
            }]
        }
    }

    return response
```

------

## クエリ文字列 - 例
<a name="lambda-examples-query-string-examples"></a>

以下の例は、クエリ文字列で Lambda@Edge を使用する方法を示しています。

**Topics**
+ [例: クエリ文字列パラメータに基づくヘッダーを追加する](#lambda-examples-header-based-on-query-string)
+ [例: キャッシュヒット率を向上させるためにクエリ文字列パラメータを正規化する](#lambda-examples-normalize-query-string-parameters)
+ [例: 認証されていないユーザーをサインインページにリダイレクトする](#lambda-examples-redirect-to-signin-page)

### 例: クエリ文字列パラメータに基づくヘッダーを追加する
<a name="lambda-examples-header-based-on-query-string"></a>

以下の例では、クエリ文字列パラメータのキーと値のペアを取得してから、それらの値に基づいてヘッダーを追加する方法を示します。

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    
    /* When a request contains a query string key-value pair but the origin server
     * expects the value in a header, you can use this Lambda function to
     * convert the key-value pair to a header. Here's what the function does:
     * 1. Parses the query string and gets the key-value pair.
     * 2. Adds a header to the request using the key-value pair that the function got in step 1.
     */

    /* Parse request querystring to get javascript object */
    const params = querystring.parse(request.querystring);

    /* Move auth param from querystring to headers */
    const headerName = 'Auth-Header';
    request.headers[headerName.toLowerCase()] = [{ key: headerName, value: params.auth }];
    delete params.auth;

    /* Update request querystring */
    request.querystring = querystring.stringify(params);

    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs, urlencode

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    '''
    When a request contains a query string key-value pair but the origin server
    expects the value in a header, you can use this Lambda function to
    convert the key-value pair to a header. Here's what the function does:
        1. Parses the query string and gets the key-value pair.
        2. Adds a header to the request using the key-value pair that the function got in step 1.
    '''

    # Parse request querystring to get dictionary/json
    params = {k : v[0] for k, v in parse_qs(request['querystring']).items()}

    # Move auth param from querystring to headers
    headerName = 'Auth-Header'
    request['headers'][headerName.lower()] = [{'key': headerName, 'value': params['auth']}]
    del params['auth']

    # Update request querystring
    request['querystring'] = urlencode(params)

    return request
```

------

### 例: キャッシュヒット率を向上させるためにクエリ文字列パラメータを正規化する
<a name="lambda-examples-normalize-query-string-parameters"></a>

次の例では、CloudFront がリクエストをオリジンに転送する前にクエリ文字列に以下の変更を行うことで、キャッシュヒット率を向上させる方法を示します。
+ パラメータの名前によりキーと値のペアをアルファベット順に並べ替える
+ キーと値のペアを小文字に変更する

詳細については、「[クエリ文字列パラメータに基づいてコンテンツをキャッシュする](QueryStringParameters.md)」を参照してください。

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    /* When you configure a distribution to forward query strings to the origin and
     * to cache based on an allowlist of query string parameters, we recommend
     * the following to improve the cache-hit ratio:
     * - Always list parameters in the same order.
     * - Use the same case for parameter names and values.
     *
     * This function normalizes query strings so that parameter names and values
     * are lowercase and parameter names are in alphabetical order.
     *
     * For more information, see:
     * https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html
     */

    console.log('Query String: ', request.querystring);

    /* Parse request query string to get javascript object */
    const params = querystring.parse(request.querystring.toLowerCase());
    const sortedParams = {};

    /* Sort param keys */
    Object.keys(params).sort().forEach(key => {
        sortedParams[key] = params[key];
    });

    /* Update request querystring with normalized  */
    request.querystring = querystring.stringify(sortedParams);

    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs, urlencode

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    '''
    When you configure a distribution to forward query strings to the origin and
    to cache based on an allowlist of query string parameters, we recommend
    the following to improve the cache-hit ratio:
    Always list parameters in the same order.
    - Use the same case for parameter names and values.

    This function normalizes query strings so that parameter names and values
    are lowercase and parameter names are in alphabetical order.

    For more information, see:
    https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html
    '''
    print("Query string: ", request["querystring"])

    # Parse request query string to get js object
    params = {k : v[0] for k, v in parse_qs(request['querystring'].lower()).items()}

    # Sort param keys
    sortedParams = sorted(params.items(), key=lambda x: x[0])

    # Update request querystring with normalized
    request['querystring'] = urlencode(sortedParams)
    
    return request
```

------

### 例: 認証されていないユーザーをサインインページにリダイレクトする
<a name="lambda-examples-redirect-to-signin-page"></a>

次の例では、ユーザーが認証情報を入力していない場合にサインインページにリダイレクトする方法を示します。

------
#### [ Node.js ]

```
'use strict';

function parseCookies(headers) {
    const parsedCookie = {};
    if (headers.cookie) {
        headers.cookie[0].value.split(';').forEach((cookie) => {
            if (cookie) {
                const parts = cookie.split('=');
                parsedCookie[parts[0].trim()] = parts[1].trim();
            }
        });
    }
    return parsedCookie;
}

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    /* Check for session-id in request cookie in viewer-request event,
     * if session-id is absent, redirect the user to sign in page with original
     * request sent as redirect_url in query params.
     */

    /* Check for session-id in cookie, if present then proceed with request */
    const parsedCookies = parseCookies(headers);
    if (parsedCookies && parsedCookies['session-id']) {
        callback(null, request);
        return;
    }

    /* URI encode the original request to be sent as redirect_url in query params */
    const encodedRedirectUrl = encodeURIComponent(`https://${headers.host[0].value}${request.uri}?${request.querystring}`);
    const response = {
        status: '302',
        statusDescription: 'Found',
        headers: {
            location: [{
                key: 'Location',
                value: `https://www.example.com/signin?redirect_url=${encodedRedirectUrl}`,
            }],
        },
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
import urllib

def parseCookies(headers):
    parsedCookie = {}
    if headers.get('cookie'):
        for cookie in headers['cookie'][0]['value'].split(';'):
            if cookie:
                parts = cookie.split('=')
                parsedCookie[parts[0].strip()] = parts[1].strip()
    return parsedCookie

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    '''
    Check for session-id in request cookie in viewer-request event,
    if session-id is absent, redirect the user to sign in page with original
    request sent as redirect_url in query params.
    '''

    # Check for session-id in cookie, if present, then proceed with request
    parsedCookies = parseCookies(headers)

    if parsedCookies and parsedCookies['session-id']:
        return request

    # URI encode the original request to be sent as redirect_url in query params
    redirectUrl = "https://%s%s?%s" % (headers['host'][0]['value'], request['uri'], request['querystring'])
    encodedRedirectUrl = urllib.parse.quote_plus(redirectUrl.encode('utf-8'))

    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': 'https://www.example.com/signin?redirect_url=%s' % encodedRedirectUrl
            }]
        }
    }
    return response
```

------

## 国またはデバイスタイプヘッダー別のコンテンツのパーソナライズ - 例
<a name="lambda-examples-redirecting-examples"></a>

以下の例は、Lambda@Edge により、ビューワーが使用しているデバイスの場所やタイプに基づいて動作をカスタマイズする方法を示しています。

**Topics**
+ [例: ビューワーリクエストを国に固有の URL にリダイレクトする](#lambda-examples-redirect-based-on-country)
+ [例: デバイスに基づいて異なるバージョンのオブジェクトを供給する](#lambda-examples-vary-on-device-type)

### 例: ビューワーリクエストを国に固有の URL にリダイレクトする
<a name="lambda-examples-redirect-based-on-country"></a>

次の例では、HTTP リダイレクト応答を国に固有の URL で生成し、ビューワーにレスポンスを返す方法を示します。これは、国ごとに異なる応答を提供する場合に便利です。次に例を示します。
+ 国別のサブドメイン (us.example.com および tw.example.com など) がある場合は、ビューワーが example.com をリクエストしたときにリダイレクト応答を生成できます。
+ 動画をストリーミングしていて、そのコンテンツを特定の国でストリーミングする権限がない場合は、その国のユーザーを別のページにリダイレクトして動画を閲覧できない理由について説明できます。

次の点に注意してください。
+ `CloudFront-Viewer-Country` ヘッダーに基づいてキャッシュするようにディストリビューションを設定する必要があります。詳細については、「[選択されたリクエストヘッダーに基づいたキャッシュ](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders)」を参照してください。
+ CloudFront は、ビューワーリクエストイベントの後に `CloudFront-Viewer-Country` ヘッダーを追加します。この例を使用するには、オリジンリクエストイベントのトリガーを作成する必要があります。

------
#### [ Node.js ]

```
'use strict';

/* This is an origin request function */
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    /*
     * Based on the value of the CloudFront-Viewer-Country header, generate an
     * HTTP status code 302 (Redirect) response, and return a country-specific
     * URL in the Location header.
     * NOTE: 1. You must configure your distribution to cache based on the
     *          CloudFront-Viewer-Country header. For more information, see
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
     *       2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
     *          request event. To use this example, you must create a trigger for the
     *          origin request event.
     */

    let url = 'https://example.com/';
    if (headers['cloudfront-viewer-country']) {
        const countryCode = headers['cloudfront-viewer-country'][0].value;
        if (countryCode === 'TW') {
            url = 'https://tw.example.com/';
        } else if (countryCode === 'US') {
            url = 'https://us.example.com/';
        }
    }

    const response = {
        status: '302',
        statusDescription: 'Found',
        headers: {
            location: [{
                key: 'Location',
                value: url,
            }],
        },
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
# This is an origin request function

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    '''
    Based on the value of the CloudFront-Viewer-Country header, generate an
    HTTP status code 302 (Redirect) response, and return a country-specific
    URL in the Location header.
    NOTE: 1. You must configure your distribution to cache based on the
            CloudFront-Viewer-Country header. For more information, see
            https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
          2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
            request event. To use this example, you must create a trigger for the
            origin request event.
    '''

    url = 'https://example.com/'
    viewerCountry = headers.get('cloudfront-viewer-country')
    if viewerCountry:
        countryCode = viewerCountry[0]['value']
        if countryCode == 'TW':
            url = 'https://tw.example.com/'
        elif countryCode == 'US':
            url = 'https://us.example.com/'

    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': url
            }]
        }
    }

    return response
```

------

### 例: デバイスに基づいて異なるバージョンのオブジェクトを供給する
<a name="lambda-examples-vary-on-device-type"></a>

次の例では、ユーザーが使用しているモバイルデバイスまたはタブレットのようなデバイスのタイプに基づいてオブジェクトの異なるバージョンを提供する方法を示します。次の点に注意してください。
+ `CloudFront-Is-*-Viewer` ヘッダーに基づいてキャッシュするようにディストリビューションを設定する必要があります。詳細については、「[選択されたリクエストヘッダーに基づいたキャッシュ](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders)」を参照してください。
+ CloudFront は、ビューワーリクエストイベントの後に `CloudFront-Is-*-Viewer` ヘッダーを追加します。この例を使用するには、オリジンリクエストイベントのトリガーを作成する必要があります。

------
#### [ Node.js ]

```
'use strict';

/* This is an origin request function */
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    /*
     * Serve different versions of an object based on the device type.
     * NOTE: 1. You must configure your distribution to cache based on the
     *          CloudFront-Is-*-Viewer headers. For more information, see
     *          the following documentation:
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-device-type
     *       2. CloudFront adds the CloudFront-Is-*-Viewer headers after the viewer
     *          request event. To use this example, you must create a trigger for the
     *          origin request event.
     */

    const desktopPath = '/desktop';
    const mobilePath = '/mobile';
    const tabletPath = '/tablet';
    const smarttvPath = '/smarttv';

    if (headers['cloudfront-is-desktop-viewer']
        && headers['cloudfront-is-desktop-viewer'][0].value === 'true') {
        request.uri = desktopPath + request.uri;
    } else if (headers['cloudfront-is-mobile-viewer']
               && headers['cloudfront-is-mobile-viewer'][0].value === 'true') {
        request.uri = mobilePath + request.uri;
    } else if (headers['cloudfront-is-tablet-viewer']
               && headers['cloudfront-is-tablet-viewer'][0].value === 'true') {
        request.uri = tabletPath + request.uri;
    } else if (headers['cloudfront-is-smarttv-viewer']
               && headers['cloudfront-is-smarttv-viewer'][0].value === 'true') {
        request.uri = smarttvPath + request.uri;
    }
    console.log(`Request uri set to "${request.uri}"`);

    callback(null, request);
};
```

------
#### [ Python ]

```
# This is an origin request function
def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    '''
    Serve different versions of an object based on the device type.
    NOTE: 1. You must configure your distribution to cache based on the
            CloudFront-Is-*-Viewer headers. For more information, see
            the following documentation:
            https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
            https://docs.aws.amazon.com/console/cloudfront/cache-on-device-type
          2. CloudFront adds the CloudFront-Is-*-Viewer headers after the viewer
            request event. To use this example, you must create a trigger for the
            origin request event.
    '''

    desktopPath = '/desktop';
    mobilePath = '/mobile';
    tabletPath = '/tablet';
    smarttvPath = '/smarttv';

    if 'cloudfront-is-desktop-viewer' in headers and headers['cloudfront-is-desktop-viewer'][0]['value'] == 'true':
        request['uri'] = desktopPath + request['uri']
    elif 'cloudfront-is-mobile-viewer' in headers and headers['cloudfront-is-mobile-viewer'][0]['value'] == 'true':
        request['uri'] = mobilePath + request['uri']
    elif 'cloudfront-is-tablet-viewer' in headers and headers['cloudfront-is-tablet-viewer'][0]['value'] == 'true':
        request['uri'] = tabletPath + request['uri']
    elif 'cloudfront-is-smarttv-viewer' in headers and headers['cloudfront-is-smarttv-viewer'][0]['value'] == 'true':
        request['uri'] = smarttvPath + request['uri']

    print("Request uri set to %s" % request['uri'])

    return request
```

------

## コンテンツベースの動的オリジンの選択 - 例
<a name="lambda-examples-content-based-routing-examples"></a>

以下の例は、Lambda@Edge を使用し、リクエスト内の情報に基づいて複数の異なるオリジンにルーティングする方法を示しています。

**Topics**
+ [例: オリジンリクエストトリガーを使用してカスタムオリジンを Amazon S3 オリジンに変更する](#lambda-examples-content-based-S3-origin-based-on-query)
+ [例: オリジンリクエストトリガーを使用して Amazon S3 オリジンのリージョンを変更する](#lambda-examples-content-based-S3-origin-request-trigger)
+ [例: オリジンリクエストトリガーを使用して Amazon S3 オリジンからカスタムオリジンに変更する](#lambda-examples-content-based-custom-origin-request-trigger)
+ [例: オリジンリクエストトリガーを使用して Amazon S3 バケットから別のバケットにトラフィックを徐々に転送する](#lambda-examples-content-based-gradual-traffic-transfer)
+ [例: オリジンリクエストトリガーを使用して Country ヘッダーに基づいてオリジンのドメイン名を変更する](#lambda-examples-content-based-geo-header)

### 例: オリジンリクエストトリガーを使用してカスタムオリジンを Amazon S3 オリジンに変更する
<a name="lambda-examples-content-based-S3-origin-based-on-query"></a>

この関数では、origin-request トリガーを使用して、リクエストのプロパティに基づいて、カスタムオリジンから、コンテンツがフェッチされる Amazon S3 オリジンに変更する方法を示しています。

------
#### [ Node.js ]

```
'use strict';

 const querystring = require('querystring');
 
 exports.handler = (event, context, callback) => {
     const request = event.Records[0].cf.request;
 
     /**
      * Reads query string to check if S3 origin should be used, and
      * if true, sets S3 origin properties.
      */
 
     const params = querystring.parse(request.querystring);
 
     if (params['useS3Origin']) {
         if (params['useS3Origin'] === 'true') {
             const s3DomainName = 'amzn-s3-demo-bucket.s3.amazonaws.com';
 
             /* Set S3 origin fields */
             request.origin = {
                 s3: {
                     domainName: s3DomainName,
                     region: '',
                     authMethod: 'origin-access-identity',
                     path: '',
                     customHeaders: {}
                 }
             };
             request.headers['host'] = [{ key: 'host', value: s3DomainName}];
         }
     }
     
    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    '''
    Reads query string to check if S3 origin should be used, and
    if true, sets S3 origin properties
    '''
    params = {k: v[0] for k, v in parse_qs(request['querystring']).items()}
    if params.get('useS3Origin') == 'true':
        s3DomainName = 'amzn-s3-demo-bucket.s3.amazonaws.com'

        # Set S3 origin fields
        request['origin'] = {
            's3': {
                'domainName': s3DomainName,
                'region': '',
                'authMethod': 'origin-access-identity',
                'path': '',
                'customHeaders': {}
            }
        }
        request['headers']['host'] = [{'key': 'host', 'value': s3DomainName}]
    return request
```

------

### 例: オリジンリクエストトリガーを使用して Amazon S3 オリジンのリージョンを変更する
<a name="lambda-examples-content-based-S3-origin-request-trigger"></a>

この関数では、origin-request トリガーを使用して、リクエストのプロパティに基づいて、コンテンツがフェッチされる Amazon S3 オリジンを変更する方法を示しています。

この例では、`CloudFront-Viewer-Country` ヘッダーの値を使用して、S3 バケットのドメイン名を、ビューワーに近いリージョンのバケットに更新します。これは、以下のように役立ちます。
+ 指定したリージョンがビューワーの国に近いほど、レイテンシーが短縮されます。
+ リクエスト元と同じ国にあるオリジンからデータが提供されることになり、データ主権が確保されます。

この例を使用するには、以下を実行する必要があります。
+ `CloudFront-Viewer-Country` ヘッダーに基づいてキャッシュするようにディストリビューションを設定します。詳細については、「[選択されたリクエストヘッダーに基づいたキャッシュ](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders)」を参照してください。
+ オリジンリクエストイベントでこの関数のトリガーを作成します。CloudFront はビューワーリクエストイベントの後に `CloudFront-Viewer-Country` ヘッダーを追加するため、この例を使用するには、オリジンリクエストに対して関数が実行されることを確認する必要があります。

**注記**  
次のコード例では、オリジンに使用しているすべての S3 バケットに同じオリジンアクセスアイデンティティ (OAI) を使用します。詳細については、「[オリジンアクセスアイデンティティ](private-content-restricting-access-to-s3.md#private-content-restricting-access-to-s3-oai)」を参照してください。

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    /**
     * This blueprint demonstrates how an origin-request trigger can be used to
     * change the origin from which the content is fetched, based on request properties.
     * In this example, we use the value of the CloudFront-Viewer-Country header
     * to update the S3 bucket domain name to a bucket in a Region that is closer to
     * the viewer.
     * 
     * This can be useful in several ways:
     *      1) Reduces latencies when the Region specified is nearer to the viewer's
     *         country.
     *      2) Provides data sovereignty by making sure that data is served from an
     *         origin that's in the same country that the request came from.
     * 
     * NOTE: 1. You must configure your distribution to cache based on the
     *          CloudFront-Viewer-Country header. For more information, see
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
     *       2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
     *          request event. To use this example, you must create a trigger for the
     *          origin request event.
     */

    const countryToRegion = {
        'DE': 'eu-central-1',
        'IE': 'eu-west-1',
        'GB': 'eu-west-2',
        'FR': 'eu-west-3',
        'JP': 'ap-northeast-1',
        'IN': 'ap-south-1'
    };

    if (request.headers['cloudfront-viewer-country']) {
        const countryCode = request.headers['cloudfront-viewer-country'][0].value;
        const region = countryToRegion[countryCode];
        
        /**
         * If the viewer's country is not in the list you specify, the request
         * goes to the default S3 bucket you've configured.
         */  
        if (region) {
            /**
             * If you've set up OAI, the bucket policy in the destination bucket
             * should allow the OAI GetObject operation, as configured by default
             * for an S3 origin with OAI. Another requirement with OAI is to provide
             * the Region so it can be used for the SIGV4 signature. Otherwise, the
             * Region is not required.
             */
            request.origin.s3.region = region;
            const domainName = `amzn-s3-demo-bucket-in-${region}.s3.${region}.amazonaws.com`;
            request.origin.s3.domainName = domainName;
            request.headers['host'] = [{ key: 'host', value: domainName }];
        }
    }

    callback(null, request);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    '''
    This blueprint demonstrates how an origin-request trigger can be used to
    change the origin from which the content is fetched, based on request properties.
    In this example, we use the value of the CloudFront-Viewer-Country header
    to update the S3 bucket domain name to a bucket in a Region that is closer to
    the viewer.
    
    This can be useful in several ways:
        1) Reduces latencies when the Region specified is nearer to the viewer's
            country.
        2) Provides data sovereignty by making sure that data is served from an
            origin that's in the same country that the request came from.
    
    NOTE: 1. You must configure your distribution to cache based on the
            CloudFront-Viewer-Country header. For more information, see
            https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
          2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
            request event. To use this example, you must create a trigger for the
            origin request event.
    '''

    countryToRegion = {
        'DE': 'eu-central-1',
        'IE': 'eu-west-1',
        'GB': 'eu-west-2',
        'FR': 'eu-west-3',
        'JP': 'ap-northeast-1',
        'IN': 'ap-south-1'
    }

    viewerCountry = request['headers'].get('cloudfront-viewer-country')
    if viewerCountry:
        countryCode = viewerCountry[0]['value']
        region = countryToRegion.get(countryCode)

        # If the viewer's country in not in the list you specify, the request
        # goes to the default S3 bucket you've configured
        if region:
            '''
            If you've set up OAI, the bucket policy in the destination bucket
            should allow the OAI GetObject operation, as configured by default
            for an S3 origin with OAI. Another requirement with OAI is to provide
            the Region so it can be used for the SIGV4 signature. Otherwise, the
            Region is not required.
            '''
            request['origin']['s3']['region'] = region
            domainName = 'amzn-s3-demo-bucket-in-{0}.s3.{0}.amazonaws.com'.format(region)
            request['origin']['s3']['domainName'] = domainName
            request['headers']['host'] = [{'key': 'host', 'value': domainName}]

    return request
```

------

### 例: オリジンリクエストトリガーを使用して Amazon S3 オリジンからカスタムオリジンに変更する
<a name="lambda-examples-content-based-custom-origin-request-trigger"></a>

この関数では、origin-request トリガーを使用して、リクエストのプロパティに基づいて、コンテンツがフェッチされるカスタムオリジンを変更する方法を示しています。

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');
 
 exports.handler = (event, context, callback) => {
     const request = event.Records[0].cf.request;
 
     /**
      * Reads query string to check if custom origin should be used, and
      * if true, sets custom origin properties.
      */
 
     const params = querystring.parse(request.querystring);
 
     if (params['useCustomOrigin']) {
         if (params['useCustomOrigin'] === 'true') {
 
             /* Set custom origin fields*/
             request.origin = {
                 custom: {
                     domainName: 'www.example.com',
                     port: 443,
                     protocol: 'https',
                     path: '',
                     sslProtocols: ['TLSv1', 'TLSv1.1'],
                     readTimeout: 5,
                     keepaliveTimeout: 5,
                     customHeaders: {}
                 }
             };
             request.headers['host'] = [{ key: 'host', value: 'www.example.com'}];
         }
     }
    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    # Reads query string to check if custom origin should be used, and
    # if true, sets custom origin properties

    params = {k: v[0] for k, v in parse_qs(request['querystring']).items()}

    if params.get('useCustomOrigin') == 'true':
            # Set custom origin fields
            request['origin'] = {
                'custom': {
                    'domainName': 'www.example.com',
                    'port': 443,
                    'protocol': 'https',
                    'path': '',
                    'sslProtocols': ['TLSv1', 'TLSv1.1'],
                    'readTimeout': 5,
                    'keepaliveTimeout': 5,
                    'customHeaders': {}
                }
            }
            request['headers']['host'] = [{'key': 'host', 'value': 'www.example.com'}]

    return request
```

------

### 例: オリジンリクエストトリガーを使用して Amazon S3 バケットから別のバケットにトラフィックを徐々に転送する
<a name="lambda-examples-content-based-gradual-traffic-transfer"></a>

この関数では、Amazon S3 バケットから別のバケットにトラフィックを制御しながら徐々に転送する方法を示しています。

------
#### [ Node.js ]

```
'use strict';

    function getRandomInt(min, max) {
        /* Random number is inclusive of min and max*/
        return Math.floor(Math.random() * (max - min + 1)) + min;
 }

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const BLUE_TRAFFIC_PERCENTAGE = 80;

    /**
      * This Lambda function demonstrates how to gradually transfer traffic from
      * one S3 bucket to another in a controlled way.
      * We define a variable BLUE_TRAFFIC_PERCENTAGE which can take values from
      * 1 to 100. If the generated randomNumber less than or equal to BLUE_TRAFFIC_PERCENTAGE, traffic
      * is re-directed to blue-bucket. If not, the default bucket that we've configured
      * is used.
      */

    const randomNumber = getRandomInt(1, 100);

if (randomNumber <= BLUE_TRAFFIC_PERCENTAGE) {
         const domainName = 'blue-bucket.s3.amazonaws.com';
         request.origin.s3.domainName = domainName;
         request.headers['host'] = [{ key: 'host', value: domainName}];
     }
    callback(null, request);
};
```

------
#### [ Python ]

```
import math
import random

def getRandomInt(min, max):
    # Random number is inclusive of min and max
    return math.floor(random.random() * (max - min + 1)) + min

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    BLUE_TRAFFIC_PERCENTAGE = 80

    '''
    This Lambda function demonstrates how to gradually transfer traffic from
    one S3 bucket to another in a controlled way.
    We define a variable BLUE_TRAFFIC_PERCENTAGE which can take values from
    1 to 100. If the generated randomNumber less than or equal to BLUE_TRAFFIC_PERCENTAGE, traffic
    is re-directed to blue-bucket. If not, the default bucket that we've configured
    is used.
    '''

    randomNumber = getRandomInt(1, 100)

    if randomNumber <= BLUE_TRAFFIC_PERCENTAGE:
        domainName = 'blue-bucket.s3.amazonaws.com'
        request['origin']['s3']['domainName'] = domainName
        request['headers']['host'] = [{'key': 'host', 'value': domainName}]

    return request
```

------

### 例: オリジンリクエストトリガーを使用して Country ヘッダーに基づいてオリジンのドメイン名を変更する
<a name="lambda-examples-content-based-geo-header"></a>

この関数では、`CloudFront-Viewer-Country` ヘッダーに基づいてオリジンのドメイン名を変更する方法を示しています。これにより、コンテンツはビューワーの国に近いオリジンから配信されます。

ディストリビューションに対してこの機能を実装すると、次のような利点があります。
+ 指定したリージョンがビューワーの国に近いほど、レイテンシーが短縮されます。
+ リクエスト元と同じ国にあるオリジンからデータが提供されることになり、データ主権が確保されます。

この機能を有効にするには、`CloudFront-Viewer-Country` ヘッダーに基づいてキャッシュするようにディストリビューションを設定する必要があります。詳細については、「[選択されたリクエストヘッダーに基づいたキャッシュ](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders)」を参照してください。

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
     const request = event.Records[0].cf.request;
     
  if (request.headers['cloudfront-viewer-country']) {
         const countryCode = request.headers['cloudfront-viewer-country'][0].value;
         if (countryCode === 'GB' || countryCode === 'DE' || countryCode === 'IE' ) {
             const domainName = 'eu.example.com';
             request.origin.custom.domainName = domainName;
             request.headers['host'] = [{key: 'host', value: domainName}];
         } 
     }
     
    callback(null, request);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    viewerCountry = request['headers'].get('cloudfront-viewer-country')
    if viewerCountry:
        countryCode = viewerCountry[0]['value']
        if countryCode == 'GB' or countryCode == 'DE' or countryCode == 'IE':
            domainName = 'eu.example.com'
            request['origin']['custom']['domainName'] = domainName
            request['headers']['host'] = [{'key': 'host', 'value': domainName}]
    return request
```

------

## エラーステータスを更新する - 例
<a name="lambda-examples-update-error-status-examples"></a>

以下の例は、Lambda@Edge を使用して、ユーザーに返すエラーステータスを変更する方法を示しています。

**Topics**
+ [例: オリジンレスポンストリガーを使用してエラーステータスコードを 200 に更新する](#lambda-examples-custom-error-static-body)
+ [例: オリジンレスポンストリガーを使用してエラーステータスコードを 302 に更新する](#lambda-examples-custom-error-new-site)

### 例: オリジンレスポンストリガーを使用してエラーステータスコードを 200 に更新する
<a name="lambda-examples-custom-error-static-body"></a>

この関数では、レスポンスステータスを 200 に更新し、以下のシナリオでビューワーに返す静的な本文コンテンツを生成する方法を示しています。
+ 関数がオリジンレスポンスでトリガーされる。
+ オリジンサーバーからのレスポンスステータスがエラーステータスコード (4xx または 5xx) である。

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;

    /**
     * This function updates the response status to 200 and generates static
     * body content to return to the viewer in the following scenario:
     * 1. The function is triggered in an origin response
     * 2. The response status from the origin server is an error status code (4xx or 5xx)
     */

    if (response.status >= 400 && response.status <= 599) {
        response.status = 200;
        response.statusDescription = 'OK';
        response.body = 'Body generation example';
    }

    callback(null, response);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    response = event['Records'][0]['cf']['response']

    '''
    This function updates the response status to 200 and generates static
    body content to return to the viewer in the following scenario:
    1. The function is triggered in an origin response
    2. The response status from the origin server is an error status code (4xx or 5xx)
    '''

    if int(response['status']) >= 400 and int(response['status']) <= 599:
        response['status'] = 200
        response['statusDescription'] = 'OK'
        response['body'] = 'Body generation example'
    return response
```

------

### 例: オリジンレスポンストリガーを使用してエラーステータスコードを 302 に更新する
<a name="lambda-examples-custom-error-new-site"></a>

この関数では、HTTP ステータスコードを 302 に更新して、異なるオリジンを設定した別のパス (キャッシュ動作) にリダイレクトする方法を示しています。次の点に注意してください。
+ 関数がオリジンレスポンスでトリガーされる。
+ オリジンサーバーからのレスポンスステータスがエラーステータスコード (4xx または 5xx) である。

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    const request = event.Records[0].cf.request;

    /**
     * This function updates the HTTP status code in the response to 302, to redirect to another
     * path (cache behavior) that has a different origin configured. Note the following:
     * 1. The function is triggered in an origin response
     * 2. The response status from the origin server is an error status code (4xx or 5xx)
     */

    if (response.status >= 400 && response.status <= 599) {
        const redirect_path = `/plan-b/path?${request.querystring}`;

        response.status = 302;
        response.statusDescription = 'Found';

        /* Drop the body, as it is not required for redirects */
        response.body = '';
        response.headers['location'] = [{ key: 'Location', value: redirect_path }];
    }

    callback(null, response);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    response = event['Records'][0]['cf']['response']
    request = event['Records'][0]['cf']['request']

    '''
    This function updates the HTTP status code in the response to 302, to redirect to another
    path (cache behavior) that has a different origin configured. Note the following:
    1. The function is triggered in an origin response
    2. The response status from the origin server is an error status code (4xx or 5xx)
    '''

    if int(response['status']) >= 400 and int(response['status']) <= 599:
        redirect_path = '/plan-b/path?%s' % request['querystring']

        response['status'] = 302
        response['statusDescription'] = 'Found'

        # Drop the body as it is not required for redirects
        response['body'] = ''
        response['headers']['location'] = [{'key': 'Location', 'value': redirect_path}]

    return response
```

------

## リクエストボディにアクセスする - 例
<a name="lambda-examples-access-request-body-examples"></a>

以下の例は、Lambda@Edge を使用して POST リクエストを操作する方法を示しています。

**注記**  
これらの例を使用するには、ディストリビューションの Lambda 関数の関連付けで *[Include body]* (ボディを含める) オプションを有効にする必要があります。デフォルトでは、有効になっていません。  
CloudFront コンソールでこの設定を有効にするには、[**Lambda 関数の関連付け**] の [**ボディを含める**] チェックボックスをオンにします。
CloudFront API または CloudFormation でこの設定を有効にするには、`LambdaFunctionAssociation` の `IncludeBody` フィールドを `true` に設定します。

**Topics**
+ [例: リクエストトリガーを使用して HTML フォームを読み込む](#lambda-examples-access-request-body-examples-read)
+ [例: リクエストトリガーを使用して HTML フォームを変更する](#lambda-examples-access-request-body-examples-replace)

### 例: リクエストトリガーを使用して HTML フォームを読み込む
<a name="lambda-examples-access-request-body-examples-read"></a>

この関数では、「お問い合わせ」フォームなど HTML フォーム (ウェブフォーム) によって生成された POST リクエストボディを処理する方法を示しています。たとえば、次のような HTML フォームがあります。

```
<html>
  <form action="https://example.com" method="post">
    Param 1: <input type="text" name="name1"><br>
    Param 2: <input type="text" name="name2"><br>
    input type="submit" value="Submit">
  </form>
</html>
```

次の関数の例では、関数は CloudFront ビューワーリクエストまたはオリジンリクエストでトリガーされる必要があります。

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');

/**
 * This function demonstrates how you can read the body of a POST request 
 * generated by an HTML form (web form). The function is triggered in a
 * CloudFront viewer request or origin request event type.
 */

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    if (request.method === 'POST') {
        /* HTTP body is always passed as base64-encoded string. Decode it. */
        const body = Buffer.from(request.body.data, 'base64').toString();
 
        /* HTML forms send the data in query string format. Parse it. */
        const params = querystring.parse(body);
 
        /* For demonstration purposes, we only log the form fields here.
         * You can put your custom logic here. For example, you can store the 
         * fields in a database, such as Amazon DynamoDB, and generate a response
         * right from your Lambda@Edge function.
         */
        for (let param in params) {
            console.log(`For "${param}" user submitted "${params[param]}".\n`);
        }
    }
    return callback(null, request);
};
```

------
#### [ Python ]

```
import base64
from urllib.parse import parse_qs

'''
Say there is a POST request body generated by an HTML such as:

<html>
<form action="https://example.com" method="post">
    Param 1: <input type="text" name="name1"><br>
    Param 2: <input type="text" name="name2"><br>
    input type="submit" value="Submit">
</form>
</html>

'''

'''
This function demonstrates how you can read the body of a POST request 
generated by an HTML form (web form). The function is triggered in a
CloudFront viewer request or origin request event type.
'''

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    if request['method'] == 'POST':
        # HTTP body is always passed as base64-encoded string. Decode it
        body = base64.b64decode(request['body']['data'])

        # HTML forms send the data in query string format. Parse it
        params = {k: v[0] for k, v in parse_qs(body).items()}

        '''
        For demonstration purposes, we only log the form fields here.
        You can put your custom logic here. For example, you can store the
        fields in a database, such as Amazon DynamoDB, and generate a response
        right from your Lambda@Edge function.
        '''
        for key, value in params.items():
            print("For %s use submitted %s" % (key, value))
            
    return request
```

------

### 例: リクエストトリガーを使用して HTML フォームを変更する
<a name="lambda-examples-access-request-body-examples-replace"></a>

この関数では、HTML フォーム (ウェブフォーム) によって生成された POST リクエストボディを変更する方法を示しています。この関数は、CloudFront ビューワーリクエストまたはオリジンリクエストでトリガーされます。

------
#### [ Node.js ]

```
'use strict';
				
const querystring = require('querystring');

exports.handler = (event, context, callback) => {
    var request = event.Records[0].cf.request;
    if (request.method === 'POST') {
        /* Request body is being replaced. To do this, update the following
        /* three fields:
         *    1) body.action to 'replace'
         *    2) body.encoding to the encoding of the new data.
         *
         *       Set to one of the following values:
         *
         *           text - denotes that the generated body is in text format.
         *               Lambda@Edge will propagate this as is.
         *           base64 - denotes that the generated body is base64 encoded.
         *               Lambda@Edge will base64 decode the data before sending
         *               it to the origin.
         *    3) body.data to the new body.
         */
        request.body.action = 'replace';
        request.body.encoding = 'text';
        request.body.data = getUpdatedBody(request);
    }
    callback(null, request);
};

function getUpdatedBody(request) {
    /* HTTP body is always passed as base64-encoded string. Decode it. */
    const body = Buffer.from(request.body.data, 'base64').toString();

    /* HTML forms send data in query string format. Parse it. */
    const params = querystring.parse(body);

    /* For demonstration purposes, we're adding one more param.
     *
     * You can put your custom logic here. For example, you can truncate long
     * bodies from malicious requests.
     */
    params['new-param-name'] = 'new-param-value';
    return querystring.stringify(params);
}
```

------
#### [ Python ]

```
import base64
from urllib.parse import parse_qs, urlencode

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    if request['method'] == 'POST':
        '''
        Request body is being replaced. To do this, update the following
        three fields:
            1) body.action to 'replace'
            2) body.encoding to the encoding of the new data.
        
            Set to one of the following values:
        
                text - denotes that the generated body is in text format.
                    Lambda@Edge will propagate this as is.
                base64 - denotes that the generated body is base64 encoded.
                    Lambda@Edge will base64 decode the data before sending
                    it to the origin.
            3) body.data to the new body.
        '''
        request['body']['action'] = 'replace'
        request['body']['encoding'] = 'text'
        request['body']['data'] = getUpdatedBody(request)
    return request

def getUpdatedBody(request):
    # HTTP body is always passed as base64-encoded string. Decode it
    body = base64.b64decode(request['body']['data'])

    # HTML forms send data in query string format. Parse it
    params = {k: v[0] for k, v in parse_qs(body).items()}

    # For demonstration purposes, we're adding one more param

    # You can put your custom logic here. For example, you can truncate long
    # bodies from malicious requests
    params['new-param-name'] = 'new-param-value'
    return urlencode(params)
```

------