

# Lambda@Edge 事件结构
事件结构

下面的主题介绍了触发 Lambda@Edge 函数时，CloudFront 传递给该函数的请求和响应事件对象。

**Topics**
+ [

## 动态源选择
](#lambda-event-content-based-routing)
+ [

## 请求事件
](#lambda-event-structure-request)
+ [

## 响应事件
](#lambda-event-structure-response)

## 动态源选择


您可以[在缓存行为中使用路径模式](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 源，但不能同时指定这两种源。

## 请求事件


下面的主题显示了 CloudFront 传递给[查看器和源请求事件](lambda-cloudfront-trigger-events.md)的 Lambda 函数的对象结构。这些示例显示了不带正文的 `GET` 请求。下面一些示例中，列出了查看器和源请求事件中的所有的可能字段。

**Topics**
+ [

### 示例查看器请求
](#example-viewer-request)
+ [

### 示例源请求
](#example-origin-request)
+ [

### 请求事件字段
](#request-event-fields)

### 示例查看器请求


下面的示例显示查看器请求事件对象。

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

### 示例源请求


下面的示例显示源请求事件对象。

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

### 请求事件字段


请求事件对象数据包含在两个子对象中：`config` (`Records.cf.config`) 和 `request` (`Records.cf.request`)。下面的列表描述了各个子对象的字段。

#### Config 对象中的字段


下面的列表介绍了 `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)：

#### 请求对象中的字段


下面的列表介绍了 `request` 对象 (`Records.cf.request`) 中的字段。

**`clientIp`（只读）**  
发出请求的查看器的 IP 地址。如果查看器使用 HTTP 代理或负载均衡器发送请求，则值为该代理或负载均衡器的 IP 地址。

**标头（读/写）**  
请求中的标头。请注意以下几点：  
+ `headers` 对象中的键为标准 HTTP 请求标头名称的小写版本。使用小写键可为您提供对标头值的不区分大小写的访问权限。
+ 每个标头对象（例如，`headers["accept"]` 或 `headers["host"]`）是一个键/值对数组。对于一个指定标头，数组为请求中的每个值包含一个键/值对。
+ `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 是否截断正文。有关更多信息，请参阅 [具有 Include Body（包含正文）选项的请求正文的限制](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` 结构*只能包含一个源*，该源可以是自定义源或 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`（读/写）（仅自定义源）**  
CloudFront 在建立与您的源的 HTTPS 连接时可使用的最小 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 存储桶的 Amazon 区域。仅当您将 `authMethod` 设置为 `origin-access-identity` 时，此项才是必需的。

## 响应事件


下面的主题显示了 CloudFront 传递给[查看器和源响应事件](lambda-cloudfront-trigger-events.md)的 Lambda 函数的对象结构。下面的示例是查看器和源响应事件中所有可能字段的列表。

**Topics**
+ [

### 示例源响应
](#lambda-event-structure-response-origin)
+ [

### 示例查看器响应
](#lambda-event-structure-response-viewer)
+ [

### 响应事件字段
](#response-event-fields)

### 示例源响应


下面的示例显示源响应事件对象。

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

### 示例查看器响应


下面的示例显示查看器响应事件对象。

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

### 响应事件字段


响应事件对象数据包含在三个子对象中：`config` (`Records.cf.config`)、`request` (`Records.cf.request`) 和 `response` (`Records.cf.response`)。有关请求对象中的字段的更多信息，请参阅[请求对象中的字段](#request-event-fields-request)。下面的列表描述了 `config` 和 `response` 子对象中的字段。

#### Config 对象中的字段


下面的列表介绍了 `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)：

#### 响应对象中的字段


下面的列表介绍了 `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"]`）是一个键/值对数组。对于一个指定标头，数组为响应中的每个值包含一个键/值对。
+ `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 状态描述。