CloudFront Functions のイベント構造 - Amazon CloudFront

CloudFront Functions のイベント構造

CloudFront Functions は、関数を実行するときに event オブジェクトを関数コードに入力として渡します。関数をテストするときは、event オブジェクトを作成し、関数に渡します。関数をテストするために event オブジェクトを作成する場合は、context オブジェクト内の distributionDomainNamedistributionIdrequestId フィールドを省略できます。ヘッダーの名前が小文字であることを確認してください (CloudFront Functions が本番環境で関数に渡す event オブジェクトはすべて該当します)。

次に、このイベントオブジェクトの構造の概要を示します。

{ "version": "1.0", "context": { <context object> }, "viewer": { <viewer object> }, "request": { <request object> }, "response": { <response object> } }

詳細については、次のトピックを参照してください。

バージョンフィールド

version フィールドには、CloudFront Functions イベントオブジェクトのバージョンを指定する文字列が含まれます。現在のバージョンは 1.0 です。

コンテキストオブジェクト

context オブジェクトには、イベントに関するコンテキスト情報が含まれます。次のフィールドが含まれています。

distributionDomainName

イベントに関連付けられたディストリビューションの CloudFront ドメイン名 (例: d111111abcdef8.cloudfront.net)。

distributionId

イベントに関連付けられたディストリビューションの ID (例: EDFDVBD6EXAMPLE) 。

eventType

イベントタイプ (viewer-request またはviewer-response)。

requestId

CloudFront リクエスト (およびそれに関連付けられたレスポンス) を一意に識別する文字列。

ビューワーオブジェクト

viewer オブジェクトには、リクエストを送信したビューワー (クライアント) の IP アドレスを値とする ip フィールドが含まれています。ビューワーリクエストが HTTP プロキシまたはロードバランサーを通して来た場合、値はプロキシまたはロードバランサーの IP アドレスです。

リクエストオブジェクト

request オブジェクトには、ビューワーから CloudFront への HTTP リクエスト表記が含まれています。関数に渡される event オブジェクトで、request オブジェクトは CloudFront がビューワーから受信した実際のリクエストを表しています。

関数コードが CloudFront に request オブジェクトを返す場合は、これと同じ構造を使用する必要があります。

request オブジェクトには、以下のフィールドが含まれています。

method

リクエストの HTTP メソッド。関数コードが request を返す場合、このフィールドは変更できません。これは、request オブジェクト内唯一の読み取り専用フィールドです。

uri

リクエストされたオブジェクトの相対パス。

注記

関数が uri 値を変更する場合、以下が適用されます。

  • 新しい uri 値は、フォワードスラッシュ (/) で始まる必要があります。

  • 関数で uri 値を変更すると、ビューワーがリクエストしているオブジェクトが変更されます。

  • 関数で uri 値を変更しても、リクエストのキャッシュ動作やオリジンリクエストの送信先は変わりません。

querystring

リクエストのクエリ文字列を表すオブジェクト。リクエストにクエリ文字列が含まれていない場合でも、request オブジェクトには空の querystring オブジェクトが含まれています。

querystring オブジェクトには、リクエストのクエリ文字列パラメータ 1 つにつき 1 つのフィールドが含まれます。

headers

リクエストの HTTP ヘッダーを表すオブジェクト。リクエストに Cookie ヘッダーが含まれている場合、それらのヘッダーは headers オブジェクトの一部ではありません。Cookieは cookies オブジェクトで個別に表示されます。

headers オブジェクトには、リクエストのヘッダー 1 つにつき 1 つのフィールドが含まれます。ヘッダー名は、イベントオブジェクトでは小文字に変換されます。また、関数コードで追加する場合、ヘッダー名を小文字にする必要があります。CloudFront Functions がイベントオブジェクトを HTTP リクエストに変換し直すと、ヘッダー名の各単語の最初の文字が大文字になります。各単語はハイフン (-) で区切られます。例えば、関数コードが example-header-name という名前のヘッダーを追加した場合、CloudFront がこれを HTTP リクエストで Example-Header-Name に変換します。

cookies

リクエスト (Cookie ヘッダー) の Cookie を表すオブジェクト。

cookies オブジェクトには、リクエストの Cookie 1 つにつき 1 つのフィールドが含まれます。

クエリ文字列、ヘッダーおよび Cookie の構造の詳細については、「クエリ文字列、ヘッダー、または Cookie の構造」を参照してください。

event オブジェクトの例については、「イベントオブジェクトの例」を参照してください。

レスポンスオブジェクト

response オブジェクトには、CloudFront Front からビューワーへの HTTP レスポンス表記が含まれています。関数に渡される event オブジェクトでは、response オブジェクトはビューワーリクエストに対する CloudFront の実際の応答を表します。

関数コードが response オブジェクトを返す場合は、これと同じ構造を使用する必要があります。

response オブジェクトには、以下のフィールドが含まれています。

statusCode

レスポンスの HTTP ステータスコード。この値は文字列ではなく整数です。

関数は statusCode を生成または変更できます。

statusDescription

レスポンスの HTTP ステータスの説明。関数コードがレスポンスを生成する場合、このフィールドはオプションです。

headers

レスポンスの HTTP ヘッダーを表すオブジェクト。レスポンスに Set-Cookie ヘッダーが含まれている場合、それらのヘッダーは headers オブジェクトの一部ではありません。Cookieは cookies オブジェクトで個別に表示されます。

headers オブジェクトには、レスポンス内のヘッダー 1 つにつき 1 つのフィールドが含まれます。ヘッダー名は、イベントオブジェクトでは小文字に変換されます。また、関数コードで追加する場合、ヘッダー名を小文字にする必要があります。CloudFront Functions がイベントオブジェクトを HTTP レスポンスに変換し直すと、ヘッダー名の各単語の最初の文字が大文字になります。各単語はハイフン (-) で区切られます。例えば、関数コードが example-header-name という名前のヘッダーを追加した場合、CloudFront がこれを HTTP レスポンスの Example-Header-Name に変換します。

cookies

レスポンス (Set-Cookie ヘッダー) で Cookie を表すオブジェクト。

cookies オブジェクトには、レスポンスの Cookie 1 つにつき 1 つのフィールドが含まれます。

body

body フィールドの追加はオプションで、関数で指定しない限り response オブジェクトには表示されません。関数は、CloudFront キャッシュまたはオリジンによって返された元の本文にアクセスできません。ビューワーレスポンス関数で body フィールドを指定しない場合、CloudFront キャッシュまたはオリジンから返された元の本文がビューワーに返されます。

CloudFront がビューワーにカスタム本文を返すようにするには、data フィールドに本文コンテンツを指定し、encoding フィールドの本文エンコーディングを指定します。エンコーディングは、プレーンテキスト ("encoding": "text") または Base64 でエンコードされたコンテンツ ("encoding": "base64") として指定できます。

ショートカットとして、本文の内容を body フィールド ("body": "<specify the body content here>") で直接指定することもできます。これを行うときは、data および encoding フィールドを省略してください。この場合、CloudFront は、本文をプレーンテキストとして扱います。

encoding

body コンテンツ (data フィールド) のエンコーディング。有効なエンコードは textbase64 のみです。

encodingbase64 と指定したが本文が有効な base64 でない場合、CloudFront はエラーを返します。

data

body コンテンツ。

変更されたステータスコードと本文の内容の詳細については、ステータスコードと本文 を参照してください。

ヘッダーと Cookie の構造の詳細については、「クエリ文字列、ヘッダー、または Cookie の構造」を参照してください。

response オブジェクトの例については、「レスポンスオブジェクトの例」を参照してください。

ステータスコードと本文

CloudFront Functions を使用して、ビューワーのレスポンスステータスコードを更新したり、レスポンス本文すべてを新しく置き換えたり、レスポンス本文を削除したりできます。CloudFront キャッシュまたはオリジンからのレスポンスを評価した後でビューワーのレスポンスを更新する一般的なシナリオには、次のようなものがあります。

  • ステータスを変更して HTTP 200 ステータスコードを設定し、ビューワーに返す静的な本文コンテンツを作成する。

  • HTTP 301 または 302 ステータスコードを設定して、ユーザーを別のウェブサイトにリダイレクトする。

  • ビューワーレスポンスの本文を配信するか削除するかを決定します。

注記

オリジンが 400 以上の HTTP エラーを返した場合、CloudFront Functions は実行されません。詳細については、「すべてのエッジ機能に対する制限」を参照してください。

HTTP レスポンスを使用する場合、CloudFront Functions は、レスポンス本文にアクセスできません。必要な値に設定することで本文コンテンツを置き換えたり、値を空に設定することで本文を削除したりできます。関数内の本文フィールドを更新しない場合は、CloudFront キャッシュまたはオリジンによって返された元の本文がビューワーに返されます。

ヒント

CloudFront Functions を使用して本文を置き換える場合は、content-encodingcontent-typecontent-length などの対応するヘッダーを新しい本文のコンテンツに合わせてください。

たとえば、CloudFront オリジンまたはキャッシュが content-encoding: gzip を返したが、ビューワーレスポンス関数が本文をプレーンテキストに設定した場合、関数は content-encodingcontent-type ヘッダーもそれに応じて変更する必要があります。

CloudFront Functions が 400 以上の HTTP エラーを返すように設定されている場合、ビューワーには同じステータスコードに対して指定したカスタムエラーページは表示されません。

クエリ文字列、ヘッダー、Cookie は同じ構造を共有します。クエリ文字列は、リクエストに表示される場合があります。ヘッダーは、リクエストとレスポンスに表示されます。Cookie は、リクエストとレスポンスに表示されます。

クエリ文字列、ヘッダーおよび Cookie はすべて、親 querystringheaderscookiesオブジェクトで一意のフィールドです。フィールド名は、クエリ文字列、ヘッダー、または Cookie の名前です。各フィールドには、クエリ文字列、ヘッダー、Cookie の値を持つ value プロパティが含まれます。

クエリ文字列値またはクエリ文字列オブジェクト

関数は、クエリ文字列オブジェクトに加えてクエリ文字列値を返すことができます。クエリ文字列値を使用して、クエリ文字列パラメータを任意のカスタム順序で配置できます。

関数コードでクエリ文字列を変更するには、次のようなコードを使用します。

var request = event.request; request.querystring = 'ID=42&Exp=1619740800&TTL=1440&NoValue=&querymv=val1&querymv=val2,val3';

ヘッダーに関する特別な考慮事項

ヘッダーのみの場合、ヘッダー名がイベントオブジェクトで小文字に変換されます。また、関数コードで追加する場合は、ヘッダー名を小文字にする必要があります。CloudFront Functions がイベントオブジェクトを HTTP リクエストまたはレスポンスに変換し直すと、ヘッダー名の各単語の最初の文字が大文字になります。各単語はハイフン (-) で区切られます。例えば、関数コードが example-header-name という名前のヘッダーを追加した場合、CloudFront がこれを HTTP リクエストまたはレスポンスの Example-Header-Name に変換します。

HTTP リクエストでの次の Host ヘッダーについて考えてみます。

Host: video.example.com

このヘッダーは、request オブジェクトで次のように表されます。

"headers": { "host": { "value": "video.example.com" } }

関数コードの Host ヘッダーにアクセスするには、次のようなコードを使用します。

var request = event.request; var host = request.headers.host.value;

関数コードでヘッダーを追加または変更するには、次のようなコードを使用します (このコードは、X-Custom-Header 値で example value という名前のヘッダーを追加します)。

var request = event.request; request.headers['x-custom-header'] = {value: 'example value'};

重複するクエリ文字列、ヘッダー、Cookie (multiValue 配列)

HTTP リクエストまたはレスポンスには、同じ名前のクエリ文字列、ヘッダー、Cookie が含まれることがあります。この場合、重複するクエリ文字列、ヘッダー、Cookie は request または response オブジェクトの 1 つのフィールドに折りたたまれていますが、このフィールドには multiValue という名前の追加のプロパティが含まれます。multiValue プロパティには、重複するクエリ文字列、ヘッダー、Cookie の各値を含む配列が含まれます。

以下の Accept ヘッダーを持つ HTTP リクエストについて考えてみます。

Accept: application/json Accept: application/xml Accept: text/html

これらのヘッダーは、request オブジェクトで次のように表されます。

"headers": { "accept": { "value": "application/json", "multiValue": [ { "value": "application/json" }, { "value": "application/xml" }, { "value": "text/html" } ] } }
注記

最初のヘッダー値 (この場合は application/json) は、value プロパティと multiValue プロパティの両方で繰り返されています。これにより、multiValue 配列をループしてすべての値にアクセスできます。

関数コードで変更するクエリ文字列、ヘッダー、または Cookie に multiValue 配列が含まれている場合、CloudFront Functions は以下のルールを使用して変更を適用します。

  1. multiValue 配列が存在し、変更がある場合は、その変更が適用されます。value プロパティの最初の要素は無視されます。

  2. それ以外の場合は、value プロパティへの変更が適用され、それ以降の値 (存在する場合) は変更されません。

この multiValue プロパティは、前の例に示すように、HTTP リクエストまたはレスポンスに同じ名前の重複するクエリ文字列、ヘッダー、Cookie のいずれかが含まれている場合にのみ使用されます。ただし、1 つのクエリ文字列、ヘッダー、または Cookie に複数の値がある場合、multiValue プロパティは使用されません。

3 つの値を含む 1 つの Accept ヘッダーを持つリクエストについて考えてみます。

Accept: application/json, application/xml, text/html

このヘッダーは、request オブジェクトで次のように表されます。

"headers": { "accept": { "value": "application/json, application/xml, text/html" } }

HTTP レスポンスの Set-Cookie ヘッダーでは、ヘッダーに Cookie の名前と値のペア、および必要に応じてセミコロンで区切られた属性のセットが含まれます。

Set-Cookie: cookie1=val1; Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT

response オブジェクトでは、これらの属性は Cookie フィールドの attributes プロパティで表されます。たとえば、前の Set-Cookie ヘッダーは次のように表されます。

"cookie1": { "value": "val1", "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT" }

レスポンスオブジェクトの例

次の例は、本文がビューワーレスポンス関数に置き換えられた response オブジェクト (ビューワーレスポンス関数の出力) を示しています。

{ "response": { "statusCode": 200, "statusDescription": "OK", "headers": { "date": { "value": "Mon, 04 Apr 2021 18:57:56 GMT" }, "server": { "value": "gunicorn/19.9.0" }, "access-control-allow-origin": { "value": "*" }, "access-control-allow-credentials": { "value": "true" }, "content-type": { "value": "text/html" }, "content-length": { "value": "86" } }, "cookies": { "ID": { "value": "id1234", "attributes": "Expires=Wed, 05 Apr 2021 07:28:00 GMT" }, "Cookie1": { "value": "val1", "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT", "multiValue": [ { "value": "val1", "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT" }, { "value": "val2", "attributes": "Path=/cat; Domain=example.com; Expires=Wed, 10 Jan 2021 07:28:00 GMT" } ] } }, // Adding the body field is optional and it will not be present in the response object // unless you specify it in your function. // Your function does not have access to the original body returned by the CloudFront // cache or origin. // If you don't specify the body field in your viewer response function, the original // body returned by the CloudFront cache or origin is returned to viewer. "body": { "encoding": "text", "data": "<!DOCTYPE html><html><body><p>Here is your custom content.</p></body></html>" } } }

イベントオブジェクトの例

以下は、完全な event オブジェクトの例です。

注記

event オブジェクトは関数への入力です。関数は、event オブジェクト全体ではなく、request または response オブジェクトだけを返します。

{ "version": "1.0", "context": { "distributionDomainName": "d111111abcdef8.cloudfront.net", "distributionId": "EDFDVBD6EXAMPLE", "eventType": "viewer-response", "requestId": "EXAMPLEntjQpEXAMPLE_SG5Z-EXAMPLEPmPfEXAMPLEu3EqEXAMPLE==" }, "viewer": {"ip": "198.51.100.11"}, "request": { "method": "GET", "uri": "/media/index.mpd", "querystring": { "ID": {"value": "42"}, "Exp": {"value": "1619740800"}, "TTL": {"value": "1440"}, "NoValue": {"value": ""}, "querymv": { "value": "val1", "multiValue": [ {"value": "val1"}, {"value": "val2,val3"} ] } }, "headers": { "host": {"value": "video.example.com"}, "user-agent": {"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0"}, "accept": { "value": "application/json", "multiValue": [ {"value": "application/json"}, {"value": "application/xml"}, {"value": "text/html"} ] }, "accept-language": {"value": "en-GB,en;q=0.5"}, "accept-encoding": {"value": "gzip, deflate, br"}, "origin": {"value": "https://website.example.com"}, "referer": {"value": "https://website.example.com/videos/12345678?action=play"}, "cloudfront-viewer-country": {"value": "GB"} }, "cookies": { "Cookie1": {"value": "value1"}, "Cookie2": {"value": "value2"}, "cookie_consent": {"value": "true"}, "cookiemv": { "value": "value3", "multiValue": [ {"value": "value3"}, {"value": "value4"} ] } } }, "response": { "statusCode": 200, "statusDescription": "OK", "headers": { "date": {"value": "Mon, 04 Apr 2021 18:57:56 GMT"}, "server": {"value": "gunicorn/19.9.0"}, "access-control-allow-origin": {"value": "*"}, "access-control-allow-credentials": {"value": "true"}, "content-type": {"value": "application/json"}, "content-length": {"value": "701"} }, "cookies": { "ID": { "value": "id1234", "attributes": "Expires=Wed, 05 Apr 2021 07:28:00 GMT" }, "Cookie1": { "value": "val1", "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT", "multiValue": [ { "value": "val1", "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT" }, { "value": "val2", "attributes": "Path=/cat; Domain=example.com; Expires=Wed, 10 Jan 2021 07:28:00 GMT" } ] } } } }