

# CloudFront Functions のイベント構造
<a name="functions-event-structure"></a>

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

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

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

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

**Topics**
+ [

## バージョンフィールド
](#functions-event-structure-version)
+ [

## コンテキストオブジェクト
](#functions-event-structure-context)
+ [

## 接続イベントの構造
](#functions-event-structure-connection)
+ [

## ビューワーオブジェクト
](#functions-event-structure-viewer)
+ [

## リクエストオブジェクト
](#functions-event-structure-request)
+ [

## レスポンスオブジェクト
](#functions-event-structure-response)
+ [

## ステータスコードと本文
](#functions-event-structure-status-body)
+ [

## クエリ文字列、ヘッダー、または Cookie の構造
](#functions-event-structure-query-header-cookie)
+ [

## レスポンスオブジェクトの例
](#functions-response-structure-example)
+ [

## イベントオブジェクトの例
](#functions-event-structure-example)

## バージョンフィールド
<a name="functions-event-structure-version"></a>

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

## コンテキストオブジェクト
<a name="functions-event-structure-context"></a>

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

**`distributionDomainName`**  
イベントに関連付けられた標準ディストリビューションの CloudFront ドメイン名 (例: d111111abcdef8.cloudfront.net)。  
`distributionDomainName` フィールドは、関数が標準ディストリビューションに対して呼び出された場合にのみ表示されます。

**`endpoint`**  
イベントに関連付けられた接続グループの CloudFront ドメイン名 (例: d111111abcdef8.cloudfront.net)。  
`endpoint` フィールドは、関数がマルチテナントディストリビューションに対して呼び出された場合にのみ表示されます。

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

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

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

## 接続イベントの構造
<a name="functions-event-structure-connection"></a>

接続関数は、ビューワー関数とは異なるイベント構造を受け取ります。接続イベントの構造とレスポンス形式の詳細については、「[CloudFront Connection Function を関連付ける](connection-functions.md)」を参照してください。

## ビューワーオブジェクト
<a name="functions-event-structure-viewer"></a>

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

## リクエストオブジェクト
<a name="functions-event-structure-request"></a>

`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 つのフィールドが含まれます。ヘッダー名は、イベントオブジェクトでは ASCII 小文字に変換されます。また、関数コードで追加する場合、ヘッダー名を ASCII 小文字にする必要があります。CloudFront Functions がイベントオブジェクトを HTTP リクエストに変換し直すと、ヘッダー名の各単語の最初の文字が ASCII 文字の場合は大文字になります。CloudFront Functions は、ヘッダー名の非 ASCII 記号には変更を適用しません。例えば、関数内では `TÈst-header` は `tÈst-header` になります。非 ASCII 記号 `È` は変更されません。  
各単語はハイフン (`-`) で区切られます。例えば、関数コードが `example-header-name` という名前のヘッダーを追加した場合、CloudFront がこれを HTTP リクエストで `Example-Header-Name` に変換します。

**`cookies`**  
リクエスト (`Cookie` ヘッダー) の Cookie を表すオブジェクト。  
`cookies` オブジェクトには、リクエストの Cookie 1 つにつき 1 つのフィールドが含まれます。

クエリ文字列、ヘッダーおよび Cookie の構造の詳細については、「[クエリ文字列、ヘッダー、または Cookie の構造](#functions-event-structure-query-header-cookie)」を参照してください。

`event` オブジェクトの例については、「[イベントオブジェクトの例](#functions-event-structure-example)」を参照してください。

## レスポンスオブジェクト
<a name="functions-event-structure-response"></a>

`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` フィールド) のエンコーディング。有効なエンコードは `text` と `base64` のみです。  
`encoding` を `base64` と指定したが本文が有効な base64 でない場合、CloudFront はエラーを返します。  
`data`  
`body` コンテンツ。

変更されたステータスコードと本文の内容の詳細については、[ステータスコードと本文](#functions-event-structure-status-body) を参照してください。

ヘッダーと Cookie の構造の詳細については、「[クエリ文字列、ヘッダー、または Cookie の構造](#functions-event-structure-query-header-cookie)」を参照してください。

`response` オブジェクトの例については、「[レスポンスオブジェクトの例](#functions-response-structure-example)」を参照してください。

## ステータスコードと本文
<a name="functions-event-structure-status-body"></a>

CloudFront Functions を使用して、ビューワーのレスポンスステータスコードを更新したり、レスポンス本文すべてを新しく置き換えたり、レスポンス本文を削除したりできます。CloudFront キャッシュまたはオリジンからのレスポンスを評価した後でビューワーのレスポンスを更新する一般的なシナリオには、次のようなものがあります。
+ ステータスを変更して HTTP 200 ステータスコードを設定し、ビューワーに返す静的な本文コンテンツを作成する。
+ HTTP 301 または 302 ステータスコードを設定して、ユーザーを別のウェブサイトにリダイレクトする。
+ ビューワーレスポンスの本文を配信するか削除するかを決定します。

**注記**  
オリジンが 400 以上の HTTP エラーを返した場合、CloudFront Functions は実行されません。詳細については、「[すべてのエッジ機能に対する制限](edge-function-restrictions-all.md)」を参照してください。

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

**ヒント**  
CloudFront Functions を使用して本文を置き換える場合は、`content-encoding`、`content-type`、`content-length` などの対応するヘッダーを新しい本文のコンテンツに合わせてください。  
たとえば、CloudFront オリジンまたはキャッシュが `content-encoding: gzip` を返したが、ビューワーレスポンス関数が本文をプレーンテキストに設定した場合、関数は `content-encoding` と `content-type` ヘッダーもそれに応じて変更する必要があります。

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

## クエリ文字列、ヘッダー、または Cookie の構造
<a name="functions-event-structure-query-header-cookie"></a>

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

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

**Contents**
+ [

### クエリ文字列値またはクエリ文字列オブジェクト
](#functions-event-structure-query)
+ [

### ヘッダーに関する特別な考慮事項
](#functions-event-structure-headers)
+ [

### 重複するクエリ文字列、ヘッダー、Cookie (`multiValue` 配列)
](#functions-event-structure-multivalue)
+ [

### Cookie 属性
](#functions-event-structure-cookie-attributes)

### クエリ文字列値またはクエリ文字列オブジェクト
<a name="functions-event-structure-query"></a>

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

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

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

### ヘッダーに関する特別な考慮事項
<a name="functions-event-structure-headers"></a>

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

**Example 例**  
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` 配列)
<a name="functions-event-structure-multivalue"></a>

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

**Example 例**  
以下の `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` プロパティの最初の要素は無視されます。

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

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

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

```
Accept: application/json, application/xml, text/html
```
このヘッダーは、`request` オブジェクトで次のように表されます。  

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

### Cookie 属性
<a name="functions-event-structure-cookie-attributes"></a>

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

**Example 例**  

```
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"
}
```

## レスポンスオブジェクトの例
<a name="functions-response-structure-example"></a>

次の例は、本文がビューワーレスポンス関数に置き換えられた `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>"
    }
  }
}
```

## イベントオブジェクトの例
<a name="functions-event-structure-example"></a>

以下は、完全な `event` オブジェクトの例です。これは、マルチテナントディストリビューションではなく、標準ディストリビューションの呼び出しの例です。マルチテナントディストリビューションの場合、`endpoint` フィールドは `distributionDomainName` の代わりに使用されます。`endpoint` の値は、イベントに関連付けられている接続グループの CloudFront ドメイン名 (d111111abcdef8.cloudfront.net など) です。

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

```
{
    "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"
                    }
                ]
            }
        }
    }
}
```