Lambda@Edge 事件结构 - Amazon CloudFront

Lambda@Edge 事件结构

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

动态源选择

您可以在缓存行为中使用路径模式,根据所请求对象的路径和名称将请求路由到源,例如 images/*.jpg。使用 Lambda@Edge,您也可以基于其他特征将请求路由到源,例如请求标头中的值。

在多种情况下,这种动态源选择会非常有用。例如,您可以跨不同地理区域中的源分配请求,帮助实现全球负载均衡。或者,您可以选择性地将请求路由到不同的源,每个服务器提供特定功能:自动程序处理、SEO 优化、身份验证等。有关演示如何使用此功能的代码示例,请参阅 基于内容的动态源选择 - 示例

在 CloudFront 源请求事件中,根据路径模式,事件结构中的 origin 对象包含有关将请求路由到的源的信息。您可以更新 origin 对象中的值,将请求路由到不同的源。更新 origin 对象时,您不需要在分配中定义源。您还可以将 Amazon S3 源对象替换为自定义源对象,或者执行相反的操作。但是,只能为每个请求指定一个源;该源可以是自定义源,也可以是 Amazon S3 源,但不能同时指定这两种源。

请求事件

下面的主题显示了 CloudFront 传递给查看器和源请求事件的 Lambda 函数的对象结构。这些示例显示了不带正文的 GET 请求。下面一些示例中,列出了查看器和源请求事件中的所有的可能字段。

示例查看器请求

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

{ "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, cf-no-cache" } ] }, "method": "GET", "origin": { "custom": { "customHeaders": {}, "domainName": "example.org", "keepaliveTimeout": 5, "path": "", "port": 443, "protocol": "https", "readTimeout": 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-requestorigin-request

requestId(只读)

一个加密字符串,唯一地标识查看器到 CloudFront 的请求。requestId 值还在 CloudFront 访问日志中显示为 x-edge-request-id。有关更多信息,请参阅 配置和使用标准日志(访问日志)标准日志文件字段

请求对象中的字段

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

clientIp(只读)

发出请求的查看器的 IP 地址。如果查看器使用 HTTP 代理或负载均衡器发送请求,则值为该代理或负载均衡器的 IP 地址。

标头(读/写)

请求中的标头。请注意以下几点:

  • headers 对象中的键为标准 HTTP 请求标头名称的小写版本。使用小写键可为您提供对标头值的不区分大小写的访问权限。

  • 每个标头对象(例如,headers["accept"]headers["host"])是一个键/值对数组。对于一个指定标头,数组为请求中的每个值包含一个键/值对。

  • key 包含 HTTP 请求中显示的标头的名称,名称区分大小写;例如 HostUser-AgentX-Forwarded-For 等等。

  • value 包含 HTTP 请求中显示的标头值。

  • 当您的 Lambda 函数添加或修改请求标头,并且您不包含标头 key 字段时,Lambda@Edge 会自动使用您提供的标头名称插入标头 key。无论您如何格式化标头名称,自动插入的标头键都将通过对每个部分使用首字母大写方式(用连字符 (-) 分隔)来格式化。

    例如,您可以不带标头键添加标头 key,如下所示:

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

    在本示例中,Lambda@Edge 会自动插入 "key": "User-Agent"

有关标头使用情况限制的信息,请参阅边缘函数的限制

method(只读)

请求中的 HTTP 方法。

querystring(读/写)

请求中的查询字符串(如果有的话)。如果请求中没有包括查询字符串,则事件结构仍包括带空值的 querystring。有关查询字符串的更多信息,请参阅 根据查询字符串参数缓存内容

uri(读/写)

所请求对象的相对路径。如果您的 Lambda 函数修改了 uri 值,请记住以下事项:

  • 新的 uri 值必须以正斜杠 (/) 开头。

  • 如果某个函数更改 uri 值,则这样会更改查看器请求的对象。

  • 如果某个函数更改 uri 值,则这样不会更改该请求或该请求发送到的源的缓存行为。

body(读/写)

HTTP 请求的正文。body 结构可以包含以下字段:

inputTruncated(只读)

一个布尔值标记,它指示 Lambda@Edge 是否截断正文。有关更多信息,请参阅具有 Include Body(包含正文)选项的请求正文的限制

action(读/写)

您打算对正文执行的操作。action 选项如下所示:

  • read-only: 这是默认值。在从 Lambda 函数返回响应时,如果 action 是只读的,Lambda@Edge 将忽略对 encodingdata 的任何更改。

  • replace: 如果要替换发送到源的正文,请指定该选项。

encoding(读/写)

正文的编码。在 Lambda@Edge 向 Lambda 函数公开正文时,它先将正文转换为 base64-encoding。如果您为 replace 选择 action 以替换正文,您可以选择使用 base64(默认编码)或 text 编码。如果将 encoding 指定为 base64,但正文不是有效的 base64,CloudFront 将返回错误。

data(读/写)

请求正文内容。

origin(读/写)(仅限原始事件)

要将请求发送到的源。origin 结构只能包含一个源,它可以是自定义源或 Amazon S3 源。源结构可以包含以下字段:

customHeaders(读/写)(自定义和 Amazon S3 源)

您可以通过为每个自定义标头指定标头名称/值对,在请求中包括自定义标头。您不能添加列入黑名单的标头,并且同名的标头不能存在于 Records.cf.request.headers 中。有关请求标头的注释也适用于自定义标头。有关更多信息,请参阅 CloudFront 无法添加到源请求的自定义标头边缘函数的限制

domainName(读/写)(自定义和 Amazon S3 源)

源的域名。域名不能为空。

  • 对于自定义源 – 指定 DNS 域名,例如 www.example.com。域名不能包含冒号 (:),也不能为 IP 地址。域名最多可以有 253 个字符。

  • 对于 Amazon S3 源 – 指定 Amazon S3 存储桶的 DNS 域名,例如 awsexamplebucket.s3.eu-west-1.amazonaws.com。名称必须最多为 128 个字符,并且必须为全小写。

path(读/写)(自定义和 Amazon S3 源)

源上的目录路径,请求应在其中查找内容。路径应该以正斜杠 (/) 开头,但不应该以正斜杠结尾(例如,它不应该以 example-path/ 结尾)。仅对于自定义源,路径应为 URL 编码,最大长度为 255 个字符。

keepaliveTimeout(读/写)(仅自定义源)

CloudFront 在接收最后一个响应数据包后应尝试与源保持连接的秒数。该值必须是 1 到 60 之间(含)的数字。

port(读/写)(仅自定义源)

自定义源中 CloudFront 应连接到的端口。端口必须为 80、443,或者是 1024 到 65535 之间(含)的数字。

protocol(读/写)(仅自定义源)

连接到您的源时 CloudFront 应使用的连接协议。该值可以是 httphttps

readTimeout(读/写)(仅自定义源)

向您的源发送请求后 CloudFront 应等待响应多长时间,以秒为单位。这还指定在 CloudFront 接收响应数据包之后应等待多长时间,然后再接收下一个数据包。该值必须是 4 到 60 之间(含)的数字。

sslProtocols(读/写)(仅自定义源)

CloudFront 在建立与您的源的 HTTPS 连接时可使用的最小 SSL/TLS 协议。可以是以下值之一:TLSv1.2TLSv1.1TLSv1SSLv3

authMethod(读/写)(仅限 Amazon S3 源)

如果您使用的是源访问身份 (OAI),请将此字段设置为 origin-access-identity,如果您未使用 OAI,则将其设置为 none。将 authMethod 设置为 origin-access-identity 时有以下几点要求:

  • 您必须指定 region(请参阅以下字段)。

  • 将请求从一个 Amazon S3 源更改为另一个源时,必须使用相同的 OAI。

  • 将请求从自定义源更改为 Amazon S3 源时,不能使用 OAI。

region(读/写)(仅限 Amazon S3 源)

您的 Amazon S3 存储桶的 AWS 区域。仅当您将 authMethod 设置为 origin-access-identity 时,此项才是必需的。

响应事件

下面的主题显示了 CloudFront 传递给查看器和源响应事件的 Lambda 函数的对象结构。下面的示例是查看器和源响应事件中所有可能字段的列表。

源响应示例

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

{ "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, cf-no-cache" } ] }, "method": "GET", "origin": { "custom": { "customHeaders": {}, "domainName": "example.org", "keepaliveTimeout": 5, "path": "", "port": 443, "protocol": "https", "readTimeout": 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)。有关请求对象中的字段的更多信息,请参阅请求对象中的字段。下面的列表描述了 configresponse 子对象中的字段。

Config 对象中的字段

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

distributionDomainName(只读)

与响应关联的分配的域名。

distributionID(只读)

与响应关联的分配的 ID。

eventType(只读)

与响应关联的触发器的类型:origin-responseviewer-response

requestId(只读)

一个加密字符串,唯一地标识与此响应关联的查看器到 CloudFront 的请求。requestId 值还在 CloudFront 访问日志中显示为 x-edge-request-id。有关更多信息,请参阅 配置和使用标准日志(访问日志)标准日志文件字段

响应对象中的字段

下面的列表介绍了 response 对象 (Records.cf.response) 中的字段。有关使用 Lambda@Edge 函数生成 HTTP 响应的信息,请参阅在请求触发器中生成 HTTP 响应

headers(读/写)

响应中的标头。请注意以下几点:

  • headers 对象中的键为标准 HTTP 请求标头名称的小写版本。使用小写键可为您提供对标头值的不区分大小写的访问权限。

  • 每个标头对象(例如,headers["content-type"]headers["content-length"])是一个键/值对数组。对于一个指定标头,数组为响应中的每个值包含一个键/值对。

  • key 包含 HTTP 响应中显示的标头的名称,名称区分大小写;例如 Content-TypeContent-Length 等等。

  • value 包含 HTTP 响应中显示的标头值。

  • 当您的 Lambda 函数添加或修改响应标头,并且您不包含标头 key 字段时,Lambda@Edge 会自动使用您提供的标头名称插入标头 key。无论您如何格式化标头名称,自动插入的标头键都将通过对每个部分使用首字母大写方式(用连字符 (-) 分隔)来格式化。

    例如,您可以不带标头键添加标头 key,如下所示:

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

    在本示例中,Lambda@Edge 会自动插入 "key": "Content-Type"

有关标头使用情况限制的信息,请参阅边缘函数的限制

status

响应的 HTTP 状态代码。

statusDescription

响应的 HTTP 状态描述。