CloudFront Functions 事件结构
CloudFront Functions 在运行函数时将 event
对象作为输入传递给函数代码。当您测试函数时,可以创建 event
对象并将其传递至您的函数。创建用于测试函数的 event
对象时,您可以省略 context
对象中的 distributionDomainName
、distributionId
和 requestId
字段。请确保标头的名称为小写字母,在生产环境中 CloudFront Functions 传递给您的函数的 event
对象中情况总是如此。
下面显示了此事件对象的结构概述。
{ "version": "1.0", "context": { <context object> }, "viewer": { <viewer object> }, "request": { <request object> }, "response": { <response object> } }
有关更多信息,请参阅以下主题:
版本字段
version
字段包含一个字符串,用于指定 CloudFront Functions 事件对象的版本。当前版本为 1.0
。
Context 对象
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 从查看器中接收的实际请求。
如果您的函数代码将 request
对象返回到 CloudFront,则它必须使用相同的结构。
request
对象包含以下字段:
method
-
请求中的 HTTP 方法。如果您的函数代码返回
request
,则无法修改此字段。这是request
对象中唯一的只读字段。 uri
-
所请求对象的相对路径。
注意
如果您的函数修改了
uri
值,则会出现以下情况:-
新的
uri
值必须以正斜杠(/
)开头。 -
如果某个函数更改
uri
值,则它会更改查看器请求的对象。 -
如果某个函数更改
uri
值,它不会更改请求或源请求发送到的源的缓存行为。
-
querystring
-
表示请求中的查询字符串的对象。如果请求中没有包括查询字符串,则
request
对象仍然包括空的querystring
对象。querystring
对象为请求中的每个查询字符串参数包含一个字段。 headers
-
表示请求中的 HTTP 标头的对象。如果请求包含任何
Cookie
标头,则这些标头不属于headers
对象的一部分。Cookies 在cookies
对象中单独表示。headers
对象为请求中的每个标头包含一个字段。标头名称在事件对象中转换为小写,当您的函数代码添加它们时,标头名称必须为小写。当 CloudFront 函数将事件对象转换回 HTTP 请求时,标头名称中每个单词的第一个字母都会大写。单词由连字符 (-
) 分隔。例如,如果您的函数代码添加了名为example-header-name
的标头,CloudFront 会将其转换为 HTTP 请求中的Example-Header-Name
。 cookies
-
表示请求中的 Cookies 的对象(
Cookie
标头)。cookies
对象为请求中的每个 Cookie 包含一个字段。
有关查询字符串、标头和 Cookies 结构的更多信息,请参阅 查询字符串、标头或 Cookie 的结构。
有关示例 event
对象,请参阅 示例事件对象。
响应对象
response
对象包含 CloudFront 至查看器 HTTP 响应的表示形式。在传递至您的函数的 event
对象中,response
对象表示 CloudFront 对查看器请求的实际响应。
如果您的函数代码返回一个 response
对象,它必须使用这个相同的结构。
response
对象包含以下字段:
statusCode
-
响应的 HTTP 状态代码。该值是一个整数,不是字符串。
您的函数可以生成或修改
statusCode
。 statusDescription
-
响应的 HTTP 状态描述。如果函数代码生成响应,则此字段为可选字段。
headers
-
表示响应中的 HTTP 标头的对象。如果响应包含任何
Set-Cookie
标头,则这些标头不属于headers
对象的一部分。Cookies 在cookies
对象中单独表示。headers
对象为响应中的每个标头包含一个字段。标头名称在事件对象中转换为小写,当您的函数代码添加它们时,标头名称必须为小写。当 CloudFront 函数将事件对象转换回 HTTP 响应时,标头名称中每个单词的第一个字母都会大写。单词由连字符 (-
) 分隔。例如,如果您的函数代码添加了名为example-header-name
的标头,CloudFront 会将其转换为 HTTP 响应中的Example-Header-Name
。 cookies
-
表示响应中的 Cookies 的对象(
Set-Cookie
标头)。cookies
对象为响应中的每个 Cookie 包含一个字段。 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
内容。
有关修改后的状态代码和正文内容的更多信息,请参阅 状态代码和正文。
有关标头和 Cookies 结构的更多信息,请参阅 查询字符串、标头或 Cookie 的结构。
有关示例 response
对象,请参阅 示例响应对象。
状态代码和正文
使用 CloudFront Functions,您可以更新查看器响应状态代码,将整个响应正文替换为新响应正文,或删除响应正文。在评估来自 CloudFront 缓存或源的响应的各个方面后更新查看器响应的一些常见场景包括:
-
更改状态以设置 HTTP 200 状态代码并创建要返回查看器的静态正文内容。
-
更改状态以设置将用户重定向到其他网站的 HTTP 301 或 302 状态代码。
-
决定是提供还是丢弃查看器响应的正文。
注意
如果源返回 400 及以上的 HTTP 错误,则 CloudFront Functions 将无法运行。有关更多信息,请参阅 所有边缘函数的限制。
当您在处理 HTTP 响应时,CloudFront Functions 无权访问响应正文。您可以通过将正文内容设置为所需值来替换正文内容,或者通过将值设置为空来删除正文。如果您不更新函数中的正文字段,CloudFront 缓存或源返回的源正文将返回到查看器。
提示
使用 CloudFront Functions 替换正文时,请确保将相应的标头(例如 content-encoding
、content-type
或 content-length
)与新的正文内容对齐。
例如,如果 CloudFront 源或缓存返回 content-encoding:
gzip
,但查看器响应函数设置的正文为纯文本,则该函数还需要相应地更改 content-encoding
和 content-type
标头。
如果您的 CloudFront 函数配置为返回 400 或以上的 HTTP 错误,则您的查看器将看不到您为相同状态代码指定的自定义错误页面。
查询字符串、标头或 Cookie 的结构
查询字符串、标头和 Cookie 共享同一个结构。查询字符串可以出现在请求中。标头出现在请求和响应中。Cookie 出现在请求和响应中。
每个查询字符串、标头或 Cookie 都是父项 querystring
、headers
或 cookies
对象内的唯一字段。字段名称是查询字符串、标头或 Cookie 的名称。每个字段都包含一个 value
属性,并带有查询字符串、标头或 Cookie 的值。
查询字符串值或查询字符串对象
除了查询字符串对象之外,函数还可以返回查询字符串值。查询字符串值可用于按任何自定义顺序排列查询字符串参数。
例 示例
要修改函数代码中的查询字符串,请使用如下代码。
var request = event.request; request.querystring = 'ID=42&Exp=1619740800&TTL=1440&NoValue=&querymv=val1&querymv=val2,val3';
标头的特殊注意事项
仅对于标头,标头名称在事件对象中转换为小写,当您的函数代码添加它们时,标头名称必须为小写。当 CloudFront 函数将事件对象转换回 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'};
重复的查询字符串、标头和 Cookies(multiValue
数组)
HTTP 请求或响应可以包含多个具有相同名称的查询字符串、标头或 Cookie。在这种情况下,重复的查询字符串、标头或 Cookie 会折叠为 request
或 response
对象中的一个字段,但此字段包含名为 multiValue
的额外属性。multiValue
属性包含一个数组,其中包含每个重复查询字符串、标头或 Cookies 的值。
例 示例
请考虑具有以下 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
数组来访问全部值。
如果函数代码修改具有 multiValue
数组的查询字符串、标头或 Cookie,CloudFront Functions 将使用以下规则来应用更改:
-
如果
multiValue
数组存在并进行了任何修改,则应用该修改。value
属性中的第一个元素将被忽略。 -
否则,将应用对
value
属性的任何修改,后续值(如果存在)保持不变。
仅当 HTTP 请求或响应中包含重复的查询字符串、标头或具有相同名称的 Cookie 时,才使用 multiValue
属性,如前面的示例所示。但是,如果单个查询字符串、标头或 Cookie 中有多个值,则不使用 multiValue
属性。
例 示例
请考虑带有一个 Accept
标头的请求,该表头中包含三个值。
Accept: application/json, application/xml, text/html
此标头在 request
对象中表示如下。
"headers": { "accept": { "value": "application/json, application/xml, text/html" } }
Cookie 属性
在 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
对象是函数的输入。您的函数只返回 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" } ] } } } }