

# 编写函数代码
<a name="writing-function-code"></a>

您可以使用 CloudFront Functions，在 JavaScript 中编写轻量级函数，以实现大规模、注重延迟的 CDN 定制设置。您的函数代码可以操作通过 CloudFront 的请求和响应、执行基本身份验证和授权、在边缘生成 HTTP 响应等。

如需为 CloudFront Functions 编写函数代码的帮助，请参阅以下主题。有关代码示例，请参阅[CloudFront 的 CloudFront Functions 示例](service_code_examples_cloudfront_functions_examples.md)以及 GitHub 上的 [amazon-cloudfront-functions](https://github.com/aws-samples/amazon-cloudfront-functions)。

**Topics**
+ [

# 确定函数用途
](function-code-choose-purpose.md)
+ [事件结构](functions-event-structure.md)
+ [JavaScript 运行时功能](functions-javascript-runtime-features.md)
+ [

# 键值存储的帮助程序方法
](functions-custom-methods.md)
+ [

# 源修改的辅助方法
](helper-functions-origin-modification.md)
+ [

# CloudFront SaaS Manager 属性的辅助方法
](saas-specific-logic-function-code.md)
+ [

# 使用 async 和 await
](async-await-syntax.md)
+ [

# CloudFront Functions 中的 CWT 支持
](cwt-support-cloudfront-functions.md)
+ [

# 通用辅助方法
](general-helper-methods.md)

# 确定函数用途
<a name="function-code-choose-purpose"></a>

在编写函数代码之前，请确定函数的用途。CloudFront Functions 中的大多数函数都具有以下用途之一。

**Topics**
+ [

## 在查看器请求事件类型中修改 HTTP 请求
](#function-code-modify-request)
+ [

## 在查看器请求事件类型中生成 HTTP 响应
](#function-code-generate-response)
+ [

## 在查看器响应事件类型中修改 HTTP 响应
](#function-code-modify-response)
+ [

## 在连接请求事件类型中验证 mTLS 连接
](#function-code-connection-request)
+ [

## 相关信息
](#related-information-cloudfront-functions-purpose)

无论函数的用途是什么，`handler` 都是任何函数的入口点。它采用一个名为 `event` 的参数，该参数通过 CloudFront 传递到函数中。`event` 是一个 JSON 对象，它包含 HTTP 请求的表示形式（以及响应，如果您的函数修改了 HTTP 响应）。

## 在查看器请求事件类型中修改 HTTP 请求
<a name="function-code-modify-request"></a>

您的函数可以修改 CloudFront 从查看器（客户端）收到的 HTTP 请求，然后将修改后的请求返回给 CloudFront 以继续处理。例如，您的函数代码可能会归一化[缓存键](understanding-the-cache-key.md)或修改请求标头。

在您创建并发布用于修改 HTTP 请求的函数后，请确保为*查看器请求*事件类型添加关联。有关更多信息，请参阅 [创建函数](functions-tutorial.md#functions-tutorial-create)。这使得该函数在每次 CloudFront 收到来自查看器的请求时运行，之后进行检查来查看所请求的对象是否在 CloudFront 缓存中。

**Example 示例**  
以下伪代码显示了修改 HTTP 请求的函数的结构。  

```
function handler(event) {
    var request = event.request;

    // Modify the request object here.

    return request;
}
```
该函数将修改后的 `request` 对象返回给 CloudFront。CloudFront 继续处理返回的请求，方法是检查 CloudFront 缓存是否存在缓存命中，并在必要时将请求发送到源。

## 在查看器请求事件类型中生成 HTTP 响应
<a name="function-code-generate-response"></a>

您的函数可以在边缘生成 HTTP 响应并直接将其返回给查看器（客户端），而无需检查缓存的响应或由 CloudFront 进一步处理。例如，您的函数代码可能会将请求重定向到新的 URL，或者检查授权并将 `401` 或 `403` 响应返回至未经授权的请求。

创建生成 HTTP 响应的函数时，请确保选择*查看器请求*事件类型。这意味着，每当 CloudFront 收到来自查看器的请求时，在 CloudFront 对请求进行任何进一步处理之前，该函数都会运行。

**Example 示例**  
以下伪代码显示了生成 HTTP 响应的函数的结构。  

```
function handler(event) {
    var request = event.request;

    var response = ...; // Create the response object here,
                        // using the request properties if needed.

    return response;
}
```
该函数将 `response` 对象返回给 CloudFront，CloudFront 立即将其返回给查看器，而无需检查 CloudFront 缓存或向源发送请求。

## 在查看器响应事件类型中修改 HTTP 响应
<a name="function-code-modify-response"></a>

您的函数可以在 CloudFront 将 HTTP 响应发送到查看器（客户端）之前修改 HTTP 响应，无论响应来自 CloudFront 缓存还是源。例如，您的函数代码可能会添加或修改响应标头、状态代码和正文内容。

当您创建修改 HTTP 响应的函数时，请确保选择*查看器响应*事件类型。这意味着，该函数在 CloudFront 向查看器返回响应之前运行，无论响应来自 CloudFront 缓存还是源。

**Example 示例**  
以下伪代码显示了修改 HTTP 响应的函数的结构。  

```
function handler(event) {
    var request = event.request;
    var response = event.response;

    // Modify the response object here,
    // using the request properties if needed.

    return response;
}
```
该函数将修改后的 `response` 对象返回给 CloudFront，CloudFront 会立即将其返回给查看器。

## 在连接请求事件类型中验证 mTLS 连接
<a name="function-code-connection-request"></a>

连接函数是一种在 TLS 连接期间运行的 CloudFront Functions，用于提供自定义验证和身份验证逻辑。连接函数目前可用于双向 TLS（mTLS）连接，您可验证客户端证书并实施标准证书验证之外的自定义身份验证逻辑。连接函数在 TLS 握手过程中运行，可根据证书属性、客户端 IP 地址或其他标准来允许或拒绝连接。

创建并发布连接函数后，请务必为*连接请求*事件类型添加与已启用 mTLS 的分配的关联。这样一来，只要客户端尝试与 CloudFront 建立 mTLS 连接，该函数就会运行。

**Example**  
以下伪代码展示了连接函数的结构：  

```
function connectionHandler(connection) {
    // Validate certificate and connection properties here.
    
    if (/* validation passes */) {
        connection.allow();
    } else {
        connection.deny();
    }
}
```
该函数使用辅助方法来确定是允许还是拒绝连接。与查看器请求和查看器响应函数不同，连接函数无法修改 HTTP 请求或响应。

## 相关信息
<a name="related-information-cloudfront-functions-purpose"></a>

有关使用 CloudFront Functions 的更多信息，请参阅以下主题：
+ [事件结构](functions-event-structure.md)
+ [JavaScript 运行时功能](functions-javascript-runtime-features.md)
+ [CloudFront Functions 示例 ](service_code_examples_cloudfront_functions_examples.md)
+ [边缘函数的限制](edge-functions-restrictions.md)

# CloudFront Functions 事件结构
<a name="functions-event-structure"></a>

CloudFront Functions 在运行函数时将 `event` 对象作为输入传递给函数代码。当您[测试函数](test-function.md)时，可以创建 `event` 对象并将其传递至您的函数。创建用于测试函数的 `event` 对象时，您可以省略 `context` 对象中的 `distributionDomainName`、`distributionId` 和 `requestId` 字段。请确保标头的名称为小写字母，在生产环境中 CloudFront Functions 传递给您的函数的 `event` 对象中情况总是如此。

下面显示了此事件对象的结构概述。

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

有关更多信息，请参阅以下主题：

**Topics**
+ [

## 版本字段
](#functions-event-structure-version)
+ [

## Context 对象
](#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`。

## Context 对象
<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-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 从查看器中接收的实际请求。

如果您的函数代码将 `request` 对象返回到 CloudFront，则它必须使用相同的结构。

`request` 对象包含以下字段：

**`method`**  
请求中的 HTTP 方法。如果您的函数代码返回 `request`，则无法修改此字段。这是 `request` 对象中唯一的只读字段。

**`uri`**  
所请求对象的相对路径。  
如果您的函数修改了 `uri` 值，则会出现以下情况：  
+ 新的 `uri` 值必须以正斜杠（`/`）开头。
+ 如果某个函数更改 `uri` 值，则它会更改查看器请求的对象。
+ 如果某个函数更改 `uri` 值，它*不会*更改请求或源请求发送到的源的缓存行为。

**`querystring`**  
表示请求中的查询字符串的对象。如果请求中没有包括查询字符串，则 `request` 对象仍然包括空的 `querystring` 对象。  
`querystring` 对象为请求中的每个查询字符串参数包含一个字段。

**`headers`**  
表示请求中的 HTTP 标头的对象。如果请求包含任何 `Cookie` 标头，则这些标头不属于 `headers` 对象的一部分。Cookies 在 `cookies` 对象中单独表示。  
`headers` 对象为请求中的每个标头包含一个字段。标头名称在事件对象中转换为 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`**  
表示请求中的 Cookies 的对象（`Cookie` 标头）。  
`cookies` 对象为请求中的每个 Cookie 包含一个字段。

有关查询字符串、标头和 Cookies 结构的更多信息，请参阅 [查询字符串、标头或 Cookie 的结构](#functions-event-structure-query-header-cookie)。

有关示例 `event` 对象，请参阅 [示例事件对象](#functions-event-structure-example)。

## 响应对象
<a name="functions-event-structure-response"></a>

`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` 内容。

有关修改后的状态代码和正文内容的更多信息，请参阅 [状态代码和正文](#functions-event-structure-status-body)。

有关标头和 Cookies 结构的更多信息，请参阅 [查询字符串、标头或 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 函数配置为返回 400 或以上的 HTTP 错误，则您的查看器将看不到您为相同状态代码指定的[自定义错误页面](creating-custom-error-pages.md)。

## 查询字符串、标头或 Cookie 的结构
<a name="functions-event-structure-query-header-cookie"></a>

查询字符串、标头和 Cookie 共享同一个结构。查询字符串可以出现在请求中。标头出现在请求和响应中。Cookie 出现在请求和响应中。

每个查询字符串、标头或 Cookie 都是父项 `querystring`、`headers` 或 `cookies` 对象内的唯一字段。字段名称是查询字符串、标头或 Cookie 的名称。每个字段都包含一个 `value` 属性，并带有查询字符串、标头或 Cookie 的值。

**Contents**
+ [

### 查询字符串值或查询字符串对象
](#functions-event-structure-query)
+ [

### 标头的特殊注意事项
](#functions-event-structure-headers)
+ [

### 重复的查询字符串、标头和 Cookies（`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 函数将事件对象转换回 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'};
```

### 重复的查询字符串、标头和 Cookies（`multiValue` 数组）
<a name="functions-event-structure-multivalue"></a>

HTTP 请求或响应可以包含多个具有相同名称的查询字符串、标头或 Cookie。在这种情况下，重复的查询字符串、标头或 Cookie 会折叠为 `request` 或 `response` 对象中的一个字段，但此字段包含名为 `multiValue` 的额外属性。`multiValue` 属性包含一个数组，其中包含每个重复查询字符串、标头或 Cookies 的值。

**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` 数组来访问*全部*值。

如果函数代码修改具有 `multiValue` 数组的查询字符串、标头或 Cookie，CloudFront Functions 将使用以下规则来应用更改：

1. 如果 `multiValue` 数组存在并进行了任何修改，则应用该修改。`value` 属性中的第一个元素将被忽略。

1. 否则，将应用对 `value` 属性的任何修改，后续值（如果存在）保持不变。

仅当 HTTP 请求或响应中包含重复的查询字符串、标头或具有相同名称的 Cookie 时，才使用 `multiValue` 属性，如前面的示例所示。但是，如果单个查询字符串、标头或 Cookie 中有多个值，则不使用 `multiValue` 属性。

**Example 示例**  
请考虑带有一个 `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"
                    }
                ]
            }
        }
    }
}
```

# 适用于 CloudFront Functions 的 JavaScript 运行时系统特征
<a name="functions-javascript-runtime-features"></a>

CloudFront Functions JavaScript 运行时系统环境符合 [ECMAScript (ES) 5.1](https://www.ecma-international.org/ecma-262/5.1/) 的要求，也支持 ES 版本 6 至 9 的某些特征。

为了获得最新的功能，建议您使用 JavaScript 运行时 2.0。

与 1.0 相比，JavaScript 运行时 2.0 有以下变化：
+ 可使用缓冲区模块方法
+ 以下非标准字符串原型方法不可用：
  + `String.prototype.bytesFrom()`
  + `String.prototype.fromBytes()`
  + `String.prototype.fromUTF8()`
  + `String.prototype.toBytes()`
  + `String.prototype.toUTF8()`
+ 加密模块包含以下更改：
  + `hash.digest()` - 如果未提供编码，则返回类型更改为 `Buffer`
  + `hmac.digest()` - 如果未提供编码，则返回类型更改为 `Buffer`
+ 有关其他新功能的更多信息，请参阅[适用于 CloudFront Functions 的 JavaScript 运行时系统 2.0 特征](functions-javascript-runtime-20.md)。

**Topics**
+ [JavaScript 运行时 1.0 功能](functions-javascript-runtime-10.md)
+ [JavaScript 运行时系统 2.0 特征](functions-javascript-runtime-20.md)

# 适用于 CloudFront Functions 的 JavaScript 运行时 1.0 功能
<a name="functions-javascript-runtime-10"></a>

CloudFront Functions JavaScript 运行时环境符合 [ECMAScript (ES) 版本 5.1](https://262.ecma-international.org/5.1/)，也支持 ES 版本 6 至 9 的某些功能。它还提供了一些不属于 ES 规范的非标准方法。

以下主题列出了所有支持的语言功能。

**Topics**
+ [

## 核心功能
](#writing-functions-javascript-features-core)
+ [

## 原语对象
](#writing-functions-javascript-features-primitive-objects)
+ [

## 内置对象
](#writing-functions-javascript-features-builtin-objects)
+ [

## 错误类型
](#writing-functions-javascript-features-error-types)
+ [

## 全局变量
](#writing-functions-javascript-features-globals)
+ [

## 内置模块
](#writing-functions-javascript-features-builtin-modules)
+ [

## 受限功能
](#writing-functions-javascript-features-restricted-features)

## 核心功能
<a name="writing-functions-javascript-features-core"></a>

支持 ES 的以下核心功能。

**类型**  
支持所有 ES 5.1 类型。这包括布尔值、数字、字符串、对象、数组、函数、函数构造函数和正则表达式。

**运算符**  
支持所有 ES 5.1 运算符。  
支持 ES 7 幂运算符 (`**`)。

**语句**  
不支持 `const` 和 `let` 语句。
支持以下 ES 5.1 语句：  
+ `break`
+ `catch`
+ `continue`
+ `do-while`
+ `else`
+ `finally`
+ `for`
+ `for-in`
+ `if`
+ `return`
+ `switch`
+ `throw`
+ `try`
+ `var`
+ `while`
+ 带标签的语句

**文本**  
支持 ES 6 模板文本：多行字符串、表达式插值和嵌套模板。

**函数**  
支持所有的 ES 5.1 函数功能。  
支持 ES 6 箭头函数，并支持 ES 6 rest 参数语法。

**Unicode**  
源文本和字符串文本可以包含 Unicode 编码的字符。还支持由六个字符组成的 Unicode 代码点转义序列（例如，`\uXXXX`）。

**严格模式**  
默认情况下，函数在严格模式下运行，因此您无需在函数代码中添加 `use strict` 语句。无法对其进行更改。

## 原语对象
<a name="writing-functions-javascript-features-primitive-objects"></a>

支持 ES 的以下原语对象。

**对象**  
支持对对象使用以下 ES 5.1 方法：  
+ `create`（没有属性列表）
+ `defineProperties`
+ `defineProperty`
+ `freeze`
+ `getOwnPropertyDescriptor`
+ `getOwnPropertyNames`
+ `getPrototypeOf`
+ `hasOwnProperty`
+ `isExtensible`
+ `isFrozen`
+ `prototype.isPrototypeOf`
+ `isSealed`
+ `keys`
+ `preventExtensions`
+ `prototype.propertyIsEnumerable`
+ `seal`
+ `prototype.toString`
+ `prototype.valueOf`
支持对对象使用以下 ES 6 方法：  
+ `assign`
+ `is`
+ `prototype.setPrototypeOf`
支持对对象使用以下 ES 8 方法：  
+ `entries`
+ `values`

**字符串**  
支持对字符串使用以下 ES 5.1 方法：  
+ `fromCharCode`
+ `prototype.charAt`
+ `prototype.concat`
+ `prototype.indexOf`
+ `prototype.lastIndexOf`
+ `prototype.match`
+ `prototype.replace`
+ `prototype.search`
+ `prototype.slice`
+ `prototype.split`
+ `prototype.substr`
+ `prototype.substring`
+ `prototype.toLowerCase`
+ `prototype.trim`
+ `prototype.toUpperCase`
支持对字符串使用以下 ES 6 方法：  
+ `fromCodePoint`
+ `prototype.codePointAt`
+ `prototype.endsWith`
+ `prototype.includes`
+ `prototype.repeat`
+ `prototype.startsWith`
支持对字符串使用以下 ES 8 方法：  
+ `prototype.padStart`
+ `prototype.padEnd`
支持对字符串使用以下 ES 9 方法：  
+ `prototype.trimStart`
+ `prototype.trimEnd`
支持对字符串使用以下非标准方法：  
+ `prototype.bytesFrom(array | string, encoding)`

  从八位数组或编码字符串创建字节字符串。字符串编码选项为 `hex`、`base64` 和 `base64url`。
+ `prototype.fromBytes(start[, end])`

  从字节字符串创建 Unicode 字符串，其中每个字节都被替换为相应的 Unicode 代码点。
+ `prototype.fromUTF8(start[, end])`

  从 UTF-8 编码的字节字符串创建 Unicode 字符串。如果编码不正确，则会返回 `null`。
+ `prototype.toBytes(start[, end])`

  从 Unicode 字符串创建字节字符串。所有字符都必须在 [0,255] 范围内。如果不在该范围内，它会返回 `null`。
+ `prototype.toUTF8(start[, end])`

  从 Unicode 字符串创建 UTF-8 编码的字节字符串。

**数字**  
支持对数字使用所有 ES 5.1 方法。  
支持对数字使用以下 ES 6 方法：  
+ `isFinite`
+ `isInteger`
+ `isNaN`
+ `isSafeInteger`
+ `parseFloat`
+ `parseInt`
+ `prototype.toExponential`
+ `prototype.toFixed`
+ `prototype.toPrecision`
+ `EPSILON`
+ `MAX_SAFE_INTEGER`
+ `MAX_VALUE`
+ `MIN_SAFE_INTEGER`
+ `MIN_VALUE`
+ `NEGATIVE_INFINITY`
+ `NaN`
+ `POSITIVE_INFINITY`

## 内置对象
<a name="writing-functions-javascript-features-builtin-objects"></a>

支持 ES 的以下内置对象。

**数学**  
支持所有 ES 5.1 数学方法。  
在 CloudFront Functions 运行时环境中，`Math.random()` 实现使用植入有函数运行时间戳的 OpenBSD `arc4random`。
支持以下 ES 6 数学方法：  
+ `acosh`
+ `asinh`
+ `atanh`
+ `cbrt`
+ `clz32`
+ `cosh`
+ `expm1`
+ `fround`
+ `hypot`
+ `imul`
+ `log10`
+ `log1p`
+ `log2`
+ `sign`
+ `sinh`
+ `tanh`
+ `trunc`
+ `E`
+ `LN10`
+ `LN2`
+ `LOG10E`
+ `LOG2E`
+ `PI`
+ `SQRT1_2`
+ `SQRT2`

**日期**  
支持所有 ES 5.1 `Date` 功能。  
出于安全原因，在单个函数运行的生命周期内，`Date` 始终返回相同的值（函数的开始时间）。有关更多信息，请参阅 [受限功能](#writing-functions-javascript-features-restricted-features)。

**函数**  
支持 `apply`、`bind` 和 `call` 方法。  
不支持函数构造函数。

**正则表达式**  
支持所有 ES 5.1 正则表达式功能。正则表达式语言与 Perl 兼容。支持 ES 9 命名的捕获组。

**JSON**  
支持所有 ES 5.1 JSON 功能，包括 `parse` 和 `stringify`。

**数组**  
支持对数组使用以下 ES 5.1 方法：  
+ `isArray`
+ `prototype.concat`
+ `prototype.every`
+ `prototype.filter`
+ `prototype.forEach`
+ `prototype.indexOf`
+ `prototype.join`
+ `prototype.lastIndexOf`
+ `prototype.map`
+ `prototype.pop`
+ `prototype.push`
+ `prototype.reduce`
+ `prototype.reduceRight`
+ `prototype.reverse`
+ `prototype.shift`
+ `prototype.slice`
+ `prototype.some`
+ `prototype.sort`
+ `prototype.splice`
+ `prototype.unshift`
支持对数组使用以下 ES 6 方法：  
+ `of`
+ `prototype.copyWithin`
+ `prototype.fill`
+ `prototype.find`
+ `prototype.findIndex`
支持对数组使用以下 ES 7 方法：  
+ `prototype.includes`

**类型化数组**  
支持对数组使用以下 ES 6 类型化数组：  
+ `Int8Array`
+ `Uint8Array`
+ `Uint8ClampedArray`
+ `Int16Array`
+ `Uint16Array`
+ `Int32Array`
+ `Uint32Array`
+ `Float32Array`
+ `Float64Array`
+ `prototype.copyWithin`
+ `prototype.fill`
+ `prototype.join`
+ `prototype.set`
+ `prototype.slice`
+ `prototype.subarray`
+ `prototype.toString`

**ArrayBuffer**  
支持对 `ArrayBuffer` 使用以下方法：  
+ `prototype.isView`
+ `prototype.slice`

**Promise**  
支持以下承诺方法：  
+ `reject`
+ `resolve`
+ `prototype.catch`
+ `prototype.finally`
+ `prototype.then`

**加密**  
加密模块提供标准哈希和基于哈希的消息身份验证码 (HMAC) 帮助程序。您可以使用 `require('crypto')` 加载模块。该模块公开了以下方法，这些方法的行为与 Node.js 对应方法完全相同：  
+ `createHash(algorithm)`
+ `hash.update(data)`
+ `hash.digest([encoding])`
+ `createHmac(algorithm, secret key)`
+ `hmac.update(data)`
+ `hmac.digest([encoding])`
有关更多信息，请参阅内置模块部分中的 [加密（哈希和 HMAC）](#writing-functions-javascript-features-builtin-modules-crypto)。

**控制台**  
这是调试的帮助对象。它只支持 `log()` 方法来记录日志消息。  
CloudFront Functions 不支持逗号语法，例如 `console.log('a', 'b')`。改为使用 `console.log('a' + ' ' + 'b')` 格式。

## 错误类型
<a name="writing-functions-javascript-features-error-types"></a>

支持以下错误对象：
+ `Error`
+ `EvalError`
+ `InternalError`
+ `MemoryError`
+ `RangeError`
+ `ReferenceError`
+ `SyntaxError`
+ `TypeError`
+ `URIError`

## 全局变量
<a name="writing-functions-javascript-features-globals"></a>

支持 `globalThis` 对象。

支持以下 ES 5.1 全局函数：
+ `decodeURI`
+ `decodeURIComponent`
+ `encodeURI`
+ `encodeURIComponent`
+ `isFinite`
+ `isNaN`
+ `parseFloat`
+ `parseInt`

支持以下全局常数：
+ `NaN`
+ `Infinity`
+ `undefined`

## 内置模块
<a name="writing-functions-javascript-features-builtin-modules"></a>

支持以下内置模块。

**Topics**
+ [

### 加密（哈希和 HMAC）
](#writing-functions-javascript-features-builtin-modules-crypto)
+ [

### 查询字符串
](#writing-functions-javascript-features-builtin-modules-query-string)

### 加密（哈希和 HMAC）
<a name="writing-functions-javascript-features-builtin-modules-crypto"></a>

加密模块 (`crypto`) 提供标准哈希和基于哈希的消息身份验证码 (HMAC) 帮助程序。您可以使用 `require('crypto')` 加载模块。该模块提供了以下方法，这些方法的行为与 Node.js 对应方法完全相同：

**哈希方法**

`crypto.createHash(algorithm)`  
创建并返回哈希对象，您可以使用给定的算法：`md5`、`sha1` 或 `sha256` 通过它生成哈希摘要。

`hash.update(data)`  
用给定的 `data` 更新哈希内容。

`hash.digest([encoding])`  
计算使用 `hash.update()` 传递的所有数据的摘要。编码可以是 `hex`、`base64` 或 `base64url`。

**HMAC 方法**

`crypto.createHmac(algorithm, secret key)`  
创建并返回使用给定的 `algorithm` 和 `secret key` 的 HMAC 对象。算法可以是 `md5`、`sha1` 或 `sha256`。

`hmac.update(data)`  
用给定的 `data` 更新 HMAC 内容。

`hmac.digest([encoding])`  
计算使用 `hmac.update()` 传递的所有数据的摘要。编码可以是 `hex`、`base64` 或 `base64url`。

### 查询字符串
<a name="writing-functions-javascript-features-builtin-modules-query-string"></a>

**注意**  
[CloudFront Functions 事件对象](functions-event-structure.md)自动为您解析 URL 查询字符串。这意味着，在大多数情况下您不需要使用此模块。

查询字符串模块 (`querystring`) 提供了解析和格式化 URL 查询字符串的方法。您可以使用 `require('querystring')` 加载模块。该模块提供了以下方法。

`querystring.escape(string)`  
URL - 对给定的 `string` 进行编码，从而返回转义的查询字符串。该方法由 `querystring.stringify()` 使用，不应直接使用。

`querystring.parse(string[, separator[, equal[, options]]])`  
解析查询字符串 (`string`) 并返回对象。  
`separator` 参数是用于在查询字符串中分隔键和值对的子字符串。默认为 `&`。  
`equal` 参数是用于在查询字符串中分隔键和值的子字符串。默认为 `=`。  
`options` 参数是具有以下键的对象：    
`decodeURIComponent function`  
用于解码查询字符串中百分比编码字符的函数。默认为 `querystring.unescape()`。  
`maxKeys number`  
要解析的最大密钥数。默认为 `1000`。使用 `0` 的值取消键的计数限制。
默认情况下，假定查询字符串中的百分比编码字符使用 UTF-8 编码。无效的 UTF-8 序列将被替换为 `U+FFFD` 替换字符。  
例如，对于以下查询字符串：  

```
'name=value&abc=xyz&abc=123'
```
`querystring.parse()` 的返回值为：  

```
{
name: 'value',
abc: ['xyz', '123']
}
```
`querystring.decode()` 是 `querystring.parse()` 的别名。

`querystring.stringify(object[, separator[, equal[, options]]])`  
序列化 `object` 并返回查询字符串。  
`separator` 参数是用于在查询字符串中分隔键和值对的子字符串。默认为 `&`。  
`equal` 参数是用于在查询字符串中分隔键和值的子字符串。默认为 `=`。  
`options` 参数是具有以下键的对象：    
`encodeURIComponent function`  
用于将 URL 不安全字符转换为查询字符串中的百分比编码的函数。默认为 `querystring.escape()`。
默认情况下，查询字符串中需要百分比编码的字符将编码为 UTF-8。要使用其他编码，请指定 `encodeURIComponent` 选项。  
例如，在下面的代码中：  

```
querystring.stringify({ name: 'value', abc: ['xyz', '123'], anotherName: '' });
```
返回值为：  

```
'name=value&abc=xyz&abc=123&anotherName='
```
`querystring.encode()` 是 `querystring.stringify()` 的别名。

`querystring.unescape(string)`  
对给定的 `string` 中的 URL 百分比编码字符进行解码，以返回未转义的查询字符串。此方法由 `querystring.parse()` 使用，不应直接使用。

## 受限功能
<a name="writing-functions-javascript-features-restricted-features"></a>

由于安全考虑，以下 JavaScript 语言功能或不受支持，或收到限制。

**动态代码评估**  
不支持动态代码评估。如果尝试，`eval()` 和 `Function` 构造函数都会引发错误。例如，`const sum = new Function('a', 'b', 'return a + b')` 引发错误。

**计时器**  
不支持 `setTimeout()`、`setImmediate()` 和 `clearTimeout()` 函数。在函数运行中没有可以推迟或生成的预置。您的函数必须同步运行才能完成。

**日期和时间戳**  
出于安全原因，无法访问高分辨率计时器。在单个函数运行的生命周期内，查询当前时间的所有 `Date` 方法始终返回相同的值。返回的时间戳是函数开始运行的时间。因此，您无法度量函数中的经过时间。

**文件系统访问**  
没有文件系统访问权限。例如，没有像 Node.js 的 `fs` 模块可以进行文件系统访问。

**处理访问权限**  
没有处理访问权限。例如，没有像 Node.js 中那样用于处理信息访问权限的 `process` 全局对象。

**环境变量**  
无法访问环境变量。  
相反，可以使用 CloudFront KeyValueStore 为 CloudFront Functions 创建集中式的键值对数据存储。借助 CloudFront KeyValueStore，无需部署代码更改即对配置数据进行动态更新。必须使用 [JavaScript 运行时 2.0](functions-javascript-runtime-20.md) 才能使用 CloudFront KeyValueStore。有关更多信息，请参阅 [Amazon CloudFront KeyValueStore](kvs-with-functions.md)。

**网络访问**  
不支持网络调用。例如，不支持 XHR、HTTP (S) 和套接字。

# 适用于 CloudFront Functions 的 JavaScript 运行时系统 2.0 特征
<a name="functions-javascript-runtime-20"></a>

CloudFront Functions JavaScript 运行时系统环境符合 [ECMAScript (ES) 5.1](https://262.ecma-international.org/5.1/) 的要求，也支持 ES 版本 6 至 9 的某些特征。它还提供了一些不属于 ES 规范的非标准方法。以下主题列出了此运行时系统中支持的所有特征。

**Topics**
+ [

## 核心功能
](#writing-functions-javascript-features-core-20)
+ [

## 原语对象
](#writing-functions-javascript-features-primitive-objects-20)
+ [

## 内置对象
](#writing-functions-javascript-features-builtin-objects-20)
+ [

## 错误类型
](#writing-functions-javascript-features-error-types-20)
+ [

## 全局变量
](#writing-functions-javascript-features-globals-20)
+ [

## 内置模块
](#writing-functions-javascript-features-builtin-modules-20)
+ [

## 受限功能
](#writing-functions-javascript-features-restricted-features-20)

## 核心功能
<a name="writing-functions-javascript-features-core-20"></a>

支持 ES 的以下核心功能。

**类型**  
支持所有 ES 5.1 类型。其中包括布尔值、数字、字符串、对象、数组、函数和正则表达式。

**运算符**  
支持所有 ES 5.1 运算符。  
支持 ES 7 幂运算符 (`**`)。

**语句**  
支持以下 ES 5.1 语句：  
+ `break`
+ `catch`
+ `continue`
+ `do-while`
+ `else`
+ `finally`
+ `for`
+ `for-in`
+ `if`
+ `label`
+ `return`
+ `switch`
+ `throw`
+ `try`
+ `var`
+ `while`
支持以下 ES 6 语句：  
+ `const`
+ `let`
支持以下 ES 8 语句：  
+ `async`
+ `await`
JavaScript 运行时 2.0 支持 `async`、`await`、`const` 和 `let`。  
`await` 只能在 `async` 函数内部使用。不支持 `async` 参数和闭包。

**文本**  
支持 ES 6 模板文本：多行字符串、表达式插值和嵌套模板。

**函数**  
支持所有的 ES 5.1 函数功能。  
支持 ES 6 箭头函数，并支持 ES 6 rest 参数语法。

**Unicode**  
源文本和字符串文本可以包含 Unicode 编码的字符。还支持由六个字符组成的 Unicode 代码点转义序列（例如，`\uXXXX`）。

**严格模式**  
默认情况下，函数在严格模式下运行，因此您无需在函数代码中添加 `use strict` 语句。无法对其进行更改。

## 原语对象
<a name="writing-functions-javascript-features-primitive-objects-20"></a>

支持 ES 的以下原语对象。

**对象**  
支持对对象使用以下 ES 5.1 方法：  
+ `Object.create()`（没有属性列表）
+ `Object.defineProperties()`
+ `Object.defineProperty()`
+ `Object.freeze()`
+ `Object.getOwnPropertyDescriptor()`
+ `Object.getOwnPropertyDescriptors()`
+ `Object.getOwnPropertyNames()`
+ `Object.getPrototypeOf()`
+ `Object.isExtensible()`
+ `Object.isFrozen()`
+ `Object.isSealed()`
+ `Object.keys()`
+ `Object.preventExtensions()`
+ `Object.seal()`
支持对对象使用以下 ES 6 方法：  
+ `Object.assign()`
支持对对象使用以下 ES 8 方法：  
+ `Object.entries()`
+ `Object.values()`
支持对对象使用以下 ES 5.1 原型方法：  
+ `Object.prototype.hasOwnProperty()`
+ `Object.prototype.isPrototypeOf()`
+ `Object.prototype.propertyIsEnumerable()`
+ `Object.prototype.toString()`
+ `Object.prototype.valueOf()`
支持对对象使用以下 ES 6 原型方法：  
+ `Object.prototype.is()`
+ `Object.prototype.setPrototypeOf()`

**字符串**  
支持对字符串使用以下 ES 5.1 方法：  
+ `String.fromCharCode()`
支持对字符串使用以下 ES 6 方法：  
+ `String.fromCodePoint()`
支持对字符串使用以下 ES 5.1 原型方法：  
+ `String.prototype.charAt()`
+ `String.prototype.concat()`
+ `String.prototype.indexOf()`
+ `String.prototype.lastIndexOf()`
+ `String.prototype.match()`
+ `String.prototype.replace()`
+ `String.prototype.search()`
+ `String.prototype.slice()`
+ `String.prototype.split()`
+ `String.prototype.substr()`
+ `String.prototype.substring()`
+ `String.prototype.toLowerCase()`
+ `String.prototype.trim()`
+ `String.prototype.toUpperCase()`
支持对字符串使用以下 ES 6 原型方法：  
+ `String.prototype.codePointAt()`
+ `String.prototype.endsWith()`
+ `String.prototype.includes()`
+ `String.prototype.repeat()`
+ `String.prototype.startsWith()`
支持对字符串使用以下 ES 8 原型方法：  
+ `String.prototype.padStart()`
+ `String.prototype.padEnd()`
支持对字符串使用以下 ES 9 原型方法：  
+ `String.prototype.trimStart()`
+ `String.prototype.trimEnd()`
支持对字符串使用以下 ES 12 原型方法：  
+ `String.prototype.replaceAll()`
**注意**  
`String.prototype.replaceAll()` 是 JavaScript 运行时系统 2.0 中的新功能。

**数字**  
支持所有 ES 5 数字。  
支持对数字使用以下 ES 6 属性：  
+ `Number.EPSILON`
+ `Number.MAX_SAFE_INTEGER`
+ `Number.MIN_SAFE_INTEGER`
+ `Number.MAX_VALUE`
+ `Number.MIN_VALUE`
+ `Number.NaN`
+ `Number.NEGATIVE_INFINITY`
+ `Number.POSITIVE_INFINITY`
支持对数字使用以下 ES 6 方法：  
+ `Number.isFinite()`
+ `Number.isInteger()`
+ `Number.isNaN()`
+ `Number.isSafeInteger()`
+ `Number.parseInt()`
+ `Number.parseFloat()`
支持对数字使用以下 ES 5.1 原型方法：  
+ `Number.prototype.toExponential()`
+ `Number.prototype.toFixed()`
+ `Number.prototype.toPrecision()`
支持 ES 12 数字分隔符。  
ES 12 数字分隔符是 JavaScript 运行时系统 2.0 中的新功能。

## 内置对象
<a name="writing-functions-javascript-features-builtin-objects-20"></a>

支持 ES 的以下内置对象。

**数学**  
支持所有 ES 5.1 数学方法。  
在 CloudFront Functions 运行时环境中，`Math.random()` 实现使用植入有函数运行时间戳的 OpenBSD `arc4random`。
支持以下 ES 6 数学属性：  
+ `Math.E`
+ `Math.LN10`
+ `Math.LN2`
+ `Math.LOG10E`
+ `Math.LOG2E`
+ `Math.PI`
+ `Math.SQRT1_2`
+ `Math.SQRT2`
支持以下 ES 6 数学方法：  
+ `Math.abs()`
+ `Math.acos()`
+ `Math.acosh()`
+ `Math.asin()`
+ `Math.asinh()`
+ `Math.atan()`
+ `Math.atan2()`
+ `Math.atanh()`
+ `Math.cbrt()`
+ `Math.ceil()`
+ `Math.clz32()`
+ `Math.cos()`
+ `Math.cosh()`
+ `Math.exp()`
+ `Math.expm1()`
+ `Math.floor()`
+ `Math.fround()`
+ `Math.hypot()`
+ `Math.imul()`
+ `Math.log()`
+ `Math.log1p()`
+ `Math.log2()`
+ `Math.log10()`
+ `Math.max()`
+ `Math.min()`
+ `Math.pow()`
+ `Math.random()`
+ `Math.round()`
+ `Math.sign()`
+ `Math.sinh()`
+ `Math.sin()`
+ `Math.sqrt()`
+ `Math.tan()`
+ `Math.tanh()`
+ `Math.trunc()`

**日期**  
支持所有 ES 5.1 `Date` 功能。  
出于安全原因，在单个函数运行的生命周期内，`Date` 始终返回相同的值（函数的开始时间）。有关更多信息，请参阅 [受限功能](functions-javascript-runtime-10.md#writing-functions-javascript-features-restricted-features)。

**函数**  
支持以下 ES 5.1 原型方法：  
+ `Function.prototype.apply()`
+ `Function.prototype.bind()`
+ `Function.prototype.call()`
不支持函数构造函数。

**正则表达式**  
支持所有 ES 5.1 正则表达式功能。正则表达式语言与 Perl 兼容。  
支持以下 ES 5.1 原型存取器属性：  
+ `RegExp.prototype.global`
+ `RegExp.prototype.ignoreCase`
+ `RegExp.protoype.multiline`
+ `RegExp.protoype.source`
+ `RegExp.prototype.sticky`
+ `RegExp.prototype.flags`
**注意**  
`RegExp.prototype.sticky` 和 `RegExp.prototype.flags` 是 JavaScript 运行时系统 2.0 中的新功能。
支持以下 ES 5.1 原型方法：  
+ `RegExp.prototype.exec()`
+ `RegExp.prototype.test()`
+ `RegExp.prototype.toString()`
+ `RegExp.prototype[@@replace]()`
+ `RegExp.prototype[@@split]()`
**注意**  
`RegExp.prototype[@@split]()` 是 JavaScript 运行时系统 2.0 中的新功能。
支持以下 ES 5.1 实例属性：  
+ `lastIndex`
支持 ES 9 命名的捕获组。

**JSON**  
支持以下 ES 5.1 方法：  
+ `JSON.parse()`
+ `JSON.stringify()`

**数组**  
支持对数组使用以下 ES 5.1 方法：  
+ `Array.isArray()`
支持对数组使用以下 ES 6 方法：  
+ `Array.of()`
支持以下 ES 5.1 原型方法：  
+ `Array.prototype.concat()`
+ `Array.prototype.every()`
+ `Array.prototype.filter()`
+ `Array.prototype.forEach()`
+ `Array.prototype.indexOf()`
+ `Array.prototype.join()`
+ `Array.prototype.lastIndexOf()`
+ `Array.prototype.map()`
+ `Array.prototype.pop()`
+ `Array.prototype.push()`
+ `Array.prototype.reduce()`
+ `Array.prototype.reduceRight()`
+ `Array.prototype.reverse()`
+ `Array.prototype.shift()`
+ `Array.prototype.slice()`
+ `Array.prototype.some()`
+ `Array.prototype.sort()`
+ `Array.prototype.splice()`
+ `Array.prototype.unshift()`
支持以下 ES 6 原型方法  
+ `Array.prototype.copyWithin()`
+ `Array.prototype.fill()`
+ `Array.prototype.find()`
+ `Array.prototype.findIndex()`
支持以下 ES 7 原型方法：  
+ `Array.prototype.includes()`

**类型化数组**  
支持以下 ES 6 类型化数组构造函数：  
+ `Float32Array`
+ `Float64Array`
+ `Int8Array`
+ `Int16Array`
+ `Int32Array`
+ `Uint8Array`
+ `Uint8ClampedArray`
+ `Uint16Array`
+ `Uint32Array`
支持以下 ES 6 方法：  
+ `TypedArray.from()`
+ `TypedArray.of()`
**注意**  
`TypedArray.from()` 和 `TypedArray.of()` 是 JavaScript 运行时系统 2.0 中的新功能。
支持以下 ES 6 原型方法：  
+ `TypedArray.prototype.copyWithin()`
+ `TypedArray.prototype.every()`
+ `TypedArray.prototype.fill()`
+ `TypedArray.prototype.filter()`
+ `TypedArray.prototype.find()`
+ `TypedArray.prototype.findIndex()`
+ `TypedArray.prototype.forEach()`
+ `TypedArray.prototype.includes()`
+ `TypedArray.prototype.indexOf()`
+ `TypedArray.prototype.join()`
+ `TypedArray.prototype.lastIndexOf()`
+ `TypedArray.prototype.map()`
+ `TypedArray.prototype.reduce()`
+ `TypedArray.prototype.reduceRight()`
+ `TypedArray.prototype.reverse()`
+ `TypedArray.prototype.some()`
+ `TypedArray.prototype.set()`
+ `TypedArray.prototype.slice()`
+ `TypedArray.prototype.sort()`
+ `TypedArray.prototype.subarray()`
+ `TypedArray.prototype.toString()`
**注意**  
`TypedArray.prototype.every()`、`TypedArray.prototype.fill()`、`TypedArray.prototype.filter()`、`TypedArray.prototype.find()`、`TypedArray.prototype.findIndex()`、`TypedArray.prototype.forEach()`、`TypedArray.prototype.includes()`、`TypedArray.prototype.indexOf()`、`TypedArray.prototype.join()`、`TypedArray.prototype.lastIndexOf()`、`TypedArray.prototype.map()`、`TypedArray.prototype.reduce()`、`TypedArray.prototype.reduceRight()`、`TypedArray.prototype.reverse()` 和 `TypedArray.prototype.some()` 是 JavaScript 运行时系统 2.0 中的新功能。

**ArrayBuffer**  
支持对 ArrayBuffer 使用以下 ES 6 方法：  
+ `isView()`
支持对 ArrayBuffer 使用以下 ES 6 原型方法：  
+ `ArrayBuffer.prototype.slice()`

**Promise**  
支持对 Promise 使用 ES 6 方法：  
+ `Promise.all()`
+ `Promise.allSettled()`
+ `Promise.any()`
+ `Promise.reject()`
+ `Promise.resolve()`
+ `Promise.race()`
**注意**  
`Promise.all()`、`Promise.allSettled()`、`Promise.any()` 和 `Promise.race()` 是 JavaScript 运行时系统 2.0 中的新功能。
支持对 Promise 使用 ES 6 原型方法：  
+ `Promise.prototype.catch()`
+ `Promise.prototype.finally()`
+ `Promise.prototype.then()`

**DataView**  
支持以下 ES 6 原型方法：  
+ `DataView.prototype.getFloat32()`
+ `DataView.prototype.getFloat64()`
+ `DataView.prototype.getInt16()`
+ `DataView.prototype.getInt32()`
+ `DataView.prototype.getInt8()`
+ `DataView.prototype.getUint16()`
+ `DataView.prototype.getUint32()`
+ `DataView.prototype.getUint8()`
+ `DataView.prototype.setFloat32()`
+ `DataView.prototype.setFloat64()`
+ `DataView.prototype.setInt16()`
+ `DataView.prototype.setInt32()`
+ `DataView.prototype.setInt8()`
+ `DataView.prototype.setUint16()`
+ `DataView.prototype.setUint32()`
+ `DataView.prototype.setUint8()`
**注意**  
所有 Dataview ES 6 原型方法都是 JavaScript 运行时系统 2.0 中的新功能。

**符号**  
支持以下 ES 6 方法：  
+ `Symbol.for()`
+ `Symbol.keyfor()`
**注意**  
所有符号 ES 6 方法都是 JavaScript 运行时系统 2.0 中的新功能。

**文本解码器**  
支持以下原型方法：  
+ `TextDecoder.prototype.decode()`
支持以下原型存取器属性：  
+ `TextDecoder.prototype.encoding`
+ `TextDecoder.prototype.fatal`
+ `TextDecoder.prototype.ignoreBOM`

**文本编码器**  
支持以下原型方法：  
+ `TextEncoder.prototype.encode()`
+ `TextEncoder.prototype.encodeInto()`

## 错误类型
<a name="writing-functions-javascript-features-error-types-20"></a>

支持以下错误对象：
+ `Error`
+ `EvalError`
+ `InternalError`
+ `RangeError`
+ `ReferenceError`
+ `SyntaxError`
+ `TypeError`
+ `URIError`

## 全局变量
<a name="writing-functions-javascript-features-globals-20"></a>

支持 `globalThis` 对象。

支持以下 ES 5.1 全局函数：
+ `decodeURI()`
+ `decodeURIComponent()`
+ `encodeURI()`
+ `encodeURIComponent()`
+ `isFinite()`
+ `isNaN()`
+ `parseFloat()`
+ `parseInt()`

支持以下 ES 6 全局函数：
+ `atob()`
+ `btoa()`
**注意**  
`atob()` 和 `btoa()` 是 JavaScript 运行时系统 2.0 中的新功能。

支持以下全局常数：
+ `NaN`
+ `Infinity`
+ `undefined`
+ `arguments`

## 内置模块
<a name="writing-functions-javascript-features-builtin-modules-20"></a>

支持以下内置模块。

**Topics**
+ [

### Buffer
](#writing-functions-javascript-features-builtin-modules-buffer-20)
+ [

### 查询字符串
](#writing-functions-javascript-features-builtin-modules-query-string-20)
+ [

### 加密
](#writing-functions-javascript-features-builtin-modules-crypto-20)

### Buffer
<a name="writing-functions-javascript-features-builtin-modules-buffer-20"></a>

该模块提供了以下方法：
+ `Buffer.alloc(size[, fill[, encoding]])`

  分配 `Buffer`。
  + `size`：缓冲区大小。输入一个整数。
  + `fill`：可选。输入字符串、`Buffer`、Uint8Array 或整数。默认值为 `0`。
  + `encoding`：可选。如果 `fill` 是字符串，请输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。
+ `Buffer.allocUnsafe(size)`

  分配一个未初始化的 `Buffer`。
  + `size`：输入一个整数。
+ `Buffer.byteLength(value[, encoding])`

  返回值的长度，以字节为单位。
  + `value`：字符串、`Buffer`、TypedArray、Dataview 或 Arraybuffer。
  + `encoding`：可选。如果 `value` 是字符串，请输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。
+ `Buffer.compare(buffer1, buffer2)`

  比较两个 `Buffer` 以帮助对数组进行排序。如果它们相同，则返回 `0`，如果 `buffer1` 排在第一位，则返回 `-1`，如果 `buffer2` 排在第一位，则返回 `1`。
  + `buffer1`：输入一个 `Buffer`。
  + `buffer2`：输入不同的 `Buffer`。
+ `Buffer.concat(list[, totalLength])`

  连接多个 `Buffer`。如果为无，则返回 `0`。最多可返回 `totalLength`。
  + `list`：输入 `Buffer` 的列表。请注意，这将被截断为 `totalLength`。
  + `totalLength`：可选。输入一个无符号整数。如果为空，则使用列表中的 `Buffer` 实例总和。
+ `Buffer.from(array)`

  从数组中创建 `Buffer`。
  + `array`：输入从 `0` 到 `255` 的字节数组。
+ `Buffer.from(arrayBuffer, byteOffset[, length]))`

  从 `arrayBuffer` 中创建视图，从偏移量 `byteOffset` 开始，长度为 `length`。
  + `arrayBuffer`：输入 `Buffer` 数组。
  + `byteOffset`：输入一个整数。
  + `length`：可选。输入一个整数。
+ `Buffer.from(buffer)`

  创建 `Buffer` 的副本。
  + `buffer`：输入一个 `Buffer`。
+ `Buffer.from(object[, offsetOrEncoding[, length]])`

  从对象创建 `Buffer`。如果 `valueOf()` 不等于对象，则返回 `Buffer.from(object.valueOf(), offsetOrEncoding, length)`。
  + `object`：输入一个对象。
  + `offsetOrEncoding`：可选。输入整数或编码字符串。
  + `length`：可选。输入一个整数。
+ `Buffer.from(string[, encoding])`

  从字符串创建 `Buffer`。
  + `string`：输入一个字符串。
  + `encoding`：可选。输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。
+ `Buffer.isBuffer(object)`

  检查 `object` 是否为缓冲区。返回 `true` 或 `false`。
  + `object`：输入一个对象。
+ `Buffer.isEncoding(encoding)`

  检查 `encoding` 是否受支持。返回 `true` 或 `false`。
  + `encoding`：可选。输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。

该模块提供以下缓冲区原型方法：
+ `Buffer.prototype.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])`

  将 `Buffer` 与目标进行比较。如果它们相同，则返回 `0`，如果 `buffer` 排在第一位，则返回 `1`，如果 `target` 排在第一位，则返回 `-1`。
  + `target`：输入一个 `Buffer`。
  + `targetStart`：可选。输入一个整数。默认值为 0。
  + `targetEnd`：可选。输入一个整数。默认为 `target` 长度。
  + `sourceStart`：可选。输入一个整数。默认值为 0。
  + `sourceEnd`：可选。输入一个整数。默认为 `Buffer` 长度。
+ `Buffer.prototype.copy(target[, targetStart[, sourceStart[, sourceEnd]]])`

  将缓冲区复制到 `target`。
  + `target`：输入 `Buffer` 或 `Uint8Array`。
  + `targetStart`：可选。输入一个整数。默认值为 0。
  + `sourceStart`：可选。输入一个整数。默认值为 0。
  + `sourceEnd`：可选。输入一个整数。默认为 `Buffer` 长度。
+ `Buffer.prototype.equals(otherBuffer)`

  将 `Buffer` 与 `otherBuffer` 进行比较。返回 `true` 或 `false`。
  + `otherBuffer`：输入一个字符串。
+ `Buffer.prototype.fill(value[, offset[, end][, encoding])`

  使用 `value` 填充 `Buffer`。
  + `value`：输入字符串、`Buffer` 或整数。
  + `offset`：可选。输入一个整数。
  + `end`：可选。输入一个整数。
  + `encoding`：可选。输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。
+ `Buffer.prototype.includes(value[, byteOffset][, encoding])`

  在 `Buffer` 中搜索 `value`。返回 `true` 或 `false`。
  + `value`：输入字符串、`Buffer`、`Uint8Array` 或整数。
  + `byteOffset`：可选。输入一个整数。
  + `encoding`：可选。输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。
+ `Buffer.prototype.indexOf(value[, byteOffset][, encoding])`

  在 `Buffer` 中搜索第一个 `value`。如果找到，则返回 `index`；如果找不到，则返回 `-1`。
  + `value`：输入一个字符串、`Buffer`、Unit8Array 或 0 到 255 之间的整数。
  + `byteOffset`：可选。输入一个整数。
  + `encoding`：可选。如果 `value` 是字符串，则输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。
+ `Buffer.prototype.lastIndexOf(value[, byteOffset][, encoding])`

  在 `Buffer` 中搜索最后一个 `value`。如果找到，则返回 `index`；如果找不到，则返回 `-1`。
  + `value`：输入一个字符串、`Buffer`、Unit8Array 或 0 到 255 之间的整数。
  + `byteOffset`：可选。输入一个整数。
  + `encoding`：可选。如果 `value` 是字符串，则输入以下值之一：`utf8`、`hex`、`base64`、`base64url`。默认值为 `utf8`。
+ `Buffer.prototype.readInt8(offset)`

  从 `Buffer` 中按 `offset` 偏移量读取 `Int8`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readIntBE(offset, byteLength)`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 `Int`。
  + `offset`：输入一个整数。
  + `byteLength`：可选。输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.readInt16BE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 `Int16`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readInt32BE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 `Int32`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readIntLE(offset, byteLength)`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 `Int`。
  + `offset`：输入一个整数。
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.readInt16LE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 `Int16`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readInt32LE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 `Int32`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readUInt8(offset)`

  从 `Buffer` 中按 `offset` 偏移量读取 `UInt8`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readUIntBE(offset, byteLength)`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 `UInt`。
  + `offset`：输入一个整数。
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.readUInt16BE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 `UInt16`。
+ 
  + `offset`：输入一个整数。
+ `Buffer.prototype.readUInt32BE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 `UInt32`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readUIntLE(offset, byteLength)`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 `UInt`。
  + `offset`：输入一个整数。
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.readUInt16LE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 `UInt16`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readUInt32LE(offset)`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 `UInt32`。
  + `offset`：输入一个整数。
+ `Buffer.prototype.readDoubleBE([offset])`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 64 位双精度浮点数。
  + `offset`：可选。输入一个整数。
+ `Buffer.prototype.readDoubleLE([offset])`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 64 位双精度浮点数。
  + `offset`：可选。输入一个整数。
+ `Buffer.prototype.readFloatBE([offset])`

  从 `Buffer` 中按 `offset` 偏移量以大端序形式读取 32 位浮点数。
  + `offset`：可选。输入一个整数。
+ `Buffer.prototype.readFloatLE([offset])`

  从 `Buffer` 中按 `offset` 偏移量以小端序形式读取 32 位浮点数。
  + `offset`：可选。输入一个整数。
+ `Buffer.prototype.subarray([start[, end]])`

  返回 `Buffer` 的一个副本，该副本经过偏移并用新的 `start` 和 `end` 进行裁剪。
  + `start`：可选。输入一个整数。默认值为 0。
  + `end`：可选。输入一个整数。默认为缓冲区长度。
+ `Buffer.prototype.swap16()`

  交换 `Buffer` 数组字节顺序，将其视为一个 16 位数字的数组。`Buffer` 长度必须可以被 2 整除，否则您将收到错误。
+ `Buffer.prototype.swap32()`

  交换 `Buffer` 数组字节顺序，将其视为一个 32 位数字的数组。`Buffer` 长度必须可以被 4 整除，否则您将收到错误。
+ `Buffer.prototype.swap64()`

  交换 `Buffer` 数组字节顺序，将其视为一个 64 位数字的数组。`Buffer` 长度必须可以被 8 整除，否则您将收到错误。
+ `Buffer.prototype.toJSON()`

  以 JSON 格式返回 `Buffer`。
+ `Buffer.prototype.toString([encoding[, start[, end]]])`

  将 `Buffer` 从 `start` 到 `end` 转换为编码字符串。
  + `encoding`：可选。输入以下值之一：`utf8`、`hex`、`base64` 或 `base64url`。默认值为 `utf8`。
  + `start`：可选。输入一个整数。默认值为 0。
  + `end`：可选。输入一个整数。默认为缓冲区长度。
+ `Buffer.prototype.write(string[, offset[, length]][, encoding])`

  如果有空格，则将编码的 `string` 写入 `Buffer`，如果空间不足，则写入截断的 `string`。
  + `string`：输入一个字符串。
  + `offset`：可选。输入一个整数。默认值为 0。
  + `length`：可选。输入一个整数。默认为字符串的长度。
  + `encoding`：可选。（可选）输入以下值之一：`utf8`、`hex`、`base64` 或 `base64url`。默认值为 `utf8`。
+ `Buffer.prototype.writeInt8(value, offset, byteLength)`

  按 `offset` 偏移量将 `byteLength` 的 `Int8` `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeIntBE(value, offset, byteLength)`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeInt16BE(value, offset, byteLength)`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeInt32BE(value, offset, byteLength)`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeIntLE(offset, byteLength)`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `offset`：输入一个整数。
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeInt16LE(offset, byteLength)`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `offset`：输入一个整数。
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeInt32LE(offset, byteLength)`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `offset`：输入一个整数。
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeUInt8(value, offset, byteLength)`

  按 `offset` 偏移量将 `byteLength` 的 `UInt8` `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeUIntBE(value, offset, byteLength)`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeUInt16BE(value, offset, byteLength)`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeUInt32BE(value, offset, byteLength)`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeUIntLE(value, offset, byteLength)`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeUInt16LE(value, offset, byteLength)`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeUInt32LE(value, offset, byteLength)`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：输入一个整数
  + `byteLength`：输入一个从 `1` 到 `6` 的整数。
+ `Buffer.prototype.writeDoubleBE(value, [offset])`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：可选。输入一个整数。默认值为 0。
+ `Buffer.prototype.writeDoubleLE(value, [offset])`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：可选。输入一个整数。默认值为 0。
+ `Buffer.prototype.writeFloatBE(value, [offset])`

  使用大端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：可选。输入一个整数。默认值为 0。
+ `Buffer.prototype.writeFloatLE(value, [offset])`

  使用小端序按 `offset` 偏移量将 `value` 写入 `Buffer`。
  + `value`：输入一个整数。
  + `offset`：可选。输入一个整数。默认值为 0。

支持以下实例方法：
+ `buffer[index]`

  在 `Buffer` 中的 `index` 处获取和设置八位字节（字节）。
  + 获取一个从 `0` 到 `255` 的数字。或者设置一个从 `0` 到 `255` 的数字。

支持以下实例属性：
+ `buffer`

  获取缓冲区的 `ArrayBuffer` 对象。
+ `byteOffset`

  获取缓冲区的 `Arraybuffer` 对象的 `byteOffset`。
+ `length`

  获取缓冲区字节计数。

**注意**  
所有缓冲区模块方法都是 JavaScript 运行时系统 2.0 中的新功能。

### 查询字符串
<a name="writing-functions-javascript-features-builtin-modules-query-string-20"></a>

**注意**  
[CloudFront Functions 事件对象](functions-event-structure.md)自动为您解析 URL 查询字符串。这意味着，在大多数情况下您不需要使用此模块。

查询字符串模块 (`querystring`) 提供了解析和格式化 URL 查询字符串的方法。您可以使用 `require('querystring')` 加载模块。该模块提供了以下方法。

`querystring.escape(string)`  
URL - 对给定的 `string` 进行编码，从而返回转义的查询字符串。该方法由 `querystring.stringify()` 使用，不应直接使用。

`querystring.parse(string[, separator[, equal[, options]]])`  
解析查询字符串 (`string`) 并返回对象。  
`separator` 参数是用于在查询字符串中分隔键和值对的子字符串。默认为 `&`。  
`equal` 参数是用于在查询字符串中分隔键和值的子字符串。默认为 `=`。  
`options` 参数是具有以下键的对象：    
`decodeURIComponent function`  
用于解码查询字符串中百分比编码字符的函数。默认为 `querystring.unescape()`。  
`maxKeys number`  
要解析的最大密钥数。默认为 `1000`。使用 `0` 的值取消键的计数限制。
默认情况下，假定查询字符串中的百分比编码字符使用 UTF-8 编码。无效的 UTF-8 序列将被替换为 `U+FFFD` 替换字符。  
例如，对于以下查询字符串：  

```
'name=value&abc=xyz&abc=123'
```
`querystring.parse()` 的返回值为：  

```
{
name: 'value',
abc: ['xyz', '123']
}
```
`querystring.decode()` 是 `querystring.parse()` 的别名。

`querystring.stringify(object[, separator[, equal[, options]]])`  
序列化 `object` 并返回查询字符串。  
`separator` 参数是用于在查询字符串中分隔键和值对的子字符串。默认为 `&`。  
`equal` 参数是用于在查询字符串中分隔键和值的子字符串。默认为 `=`。  
`options` 参数是具有以下键的对象：    
`encodeURIComponent function`  
用于将 URL 不安全字符转换为查询字符串中的百分比编码的函数。默认为 `querystring.escape()`。
默认情况下，查询字符串中需要百分比编码的字符将编码为 UTF-8。要使用其他编码，请指定 `encodeURIComponent` 选项。  
例如，在下面的代码中：  

```
querystring.stringify({ name: 'value', abc: ['xyz', '123'], anotherName: '' });
```
返回值为：  

```
'name=value&abc=xyz&abc=123&anotherName='
```
`querystring.encode()` 是 `querystring.stringify()` 的别名。

`querystring.unescape(string)`  
对给定的 `string` 中的 URL 百分比编码字符进行解码，以返回未转义的查询字符串。此方法由 `querystring.parse()` 使用，不应直接使用。

### 加密
<a name="writing-functions-javascript-features-builtin-modules-crypto-20"></a>

加密模块 (`crypto`) 提供标准哈希和基于哈希的消息身份验证码 (HMAC) 帮助程序。您可以使用 `require('crypto')` 加载模块。

**哈希方法**

`crypto.createHash(algorithm)`  
创建并返回哈希对象，您可以使用给定的算法：`md5`、`sha1` 或 `sha256` 通过它生成哈希摘要。

`hash.update(data)`  
用给定的 `data` 更新哈希内容。

`hash.digest([encoding])`  
计算使用 `hash.update()` 传递的所有数据的摘要。编码可以是 `hex`、`base64` 或 `base64url`。

**HMAC 方法**

`crypto.createHmac(algorithm, secret key)`  
创建并返回使用给定的 `algorithm` 和 `secret key` 的 HMAC 对象。算法可以是 `md5`、`sha1` 或 `sha256`。

`hmac.update(data)`  
用给定的 `data` 更新 HMAC 内容。

`hmac.digest([encoding])`  
计算使用 `hmac.update()` 传递的所有数据的摘要。编码可以是 `hex`、`base64` 或 `base64url`。

## 受限功能
<a name="writing-functions-javascript-features-restricted-features-20"></a>

由于安全考虑，以下 JavaScript 语言功能或不受支持，或收到限制。

**动态代码评估**  
不支持动态代码评估。如果尝试，`eval()` 和 `Function` 构造函数都会引发错误。例如，`const sum = new Function('a', 'b', 'return a + b')` 引发错误。

**计时器**  
不支持 `setTimeout()`、`setImmediate()` 和 `clearTimeout()` 函数。在函数运行中没有可以推迟或生成的预置。您的函数必须同步运行才能完成。

**日期和时间戳**  
出于安全原因，无法访问高分辨率计时器。在单个函数运行的生命周期内，查询当前时间的所有 `Date` 方法始终返回相同的值。返回的时间戳是函数开始运行的时间。因此，您无法度量函数中的经过时间。

**文件系统访问**  
没有文件系统访问权限。例如，没有像 Node.js 的 `fs` 模块可以进行文件系统访问。

**处理访问权限**  
没有处理访问权限。例如，没有像 Node.js 中那样用于处理信息访问权限的 `process` 全局对象。

**环境变量**  
无法访问环境变量。相反，可以使用 CloudFront KeyValueStore 为 CloudFront Functions 创建集中式的键值对数据存储。借助 CloudFront KeyValueStore，无需部署代码更改即对配置数据进行动态更新。有关更多信息，请参阅 [Amazon CloudFront KeyValueStore](kvs-with-functions.md)。

**网络访问**  
不支持网络调用。例如，不支持 XHR、HTTP (S) 和套接字。

# 键值存储的帮助程序方法
<a name="functions-custom-methods"></a>

**注意**  
来自 CloudFront Functions 的键值存储辅助方法调用不会触发 AWS CloudTrail 数据事件。这些事件不会记录在 CloudTrail 事件历史记录中。有关更多信息，请参阅 [使用 AWS CloudTrail 记录 Amazon CloudFront API 调用](logging_using_cloudtrail.md)。

如果您使用 [CloudFront 键值存储](kvs-with-functions.md)在您创建的函数中包含键值，则本节适用。CloudFront Functions 有一个模块，该模块提供了三种用于从键值存储中读取值的帮助程序方法。

要在函数代码中使用此模块，请确保已将[相关键值存储](kvs-with-functions-associate.md)与该函数关联。

接下来，在函数代码的第一行中添加以下语句：

```
import cf from 'cloudfront';
const kvsHandle = cf.kvs();
```



## `get()` 方法
<a name="functions-custom-methods-get"></a>

使用此方法可返回您指定的键名称的键值。

**请求**

```
get("key", options);
```
+ `key`：需要提取其值的键的名称
+ `options`：包含一个选项 `format`。它可以确保函数正确地解析数据。可能的值：
  + `string`：（默认）UTF8 编码
  + `json` 
  + `bytes`：原始二进制数据缓冲区

**请求示例**

```
const value = await kvsHandle.get("myFunctionKey", { format: "string"});
```

**响应**

响应是以使用 `options` 请求的格式解析为值的 `promise`。默认情况下，此值以字符串的形式返回。

### 错误处理
<a name="error-handling-exists-method"></a>

当您请求的键在关联的键值存储中不存在时，`get()` 方法将返回错误。要管理此使用案例，可以在代码中添加 `try` 和 `catch` 块。

**警告**  
使用 Promise 组合器（例如 `Promise.all`、`Promise.any`）和 Promise 链方法（例如 `then` 和 `catch`）可能需要大量的函数内存使用量。如果您的函数超过了[最大函数内存](cloudfront-limits.md#limits-functions)配额，它将无法执行。为避免出现此错误，我们建议您按顺序或循环使用 `await` 语法来请求多个值。  
**示例**  

```
var value1 = await kvs.get('key1');
var value2 = await kvs.get('key2');
```
目前，使用 Promise 组合器获取多个值并不能提高性能，如下例所示。  

```
var values = await Promise.all([kvs.get('key1'), kvs.get('key2'),]);
```

## `exists()` 方法
<a name="functions-custom-methods-exists"></a>

使用该方法可确定此键在键值存储中是否存在。

**请求**

```
exists("key");
```

**请求示例**

```
const exist = await kvsHandle.exists("myFunctionkey");
```

**响应**

响应是返回布尔值（`true` 或 `false`）的 `promise`。该值指定此键在键值存储中是否存在。

## `meta()` 方法
<a name="functions-custom-methods-meta"></a>

使用此方法返回有关键值存储的元数据。

**请求**

```
meta();
```

**请求示例**

```
const meta = await kvsHandle.meta();
```

**响应**

响应是解析为具有以下属性的对象的 `promise`：
+ `creationDateTime`：创建键值存储的日期和时间，采用 ISO 8601 格式。
+ `lastUpdatedDateTime`：上次从源中同步键值存储的日期和时间，采用 ISO 8601 格式。该值不包括向边缘传播的时间。
+ `keyCount`：上次从源同步后 KVS 中的键总数。

**响应示例**

```
{keyCount:3,creationDateTime:2023-11-30T23:07:55.765Z,lastUpdatedDateTime:2023-12-15T03:57:52.411Z}
```

# 源修改的辅助方法
<a name="helper-functions-origin-modification"></a>

如果您在 CloudFront Functions 代码中动态更新或更改请求中使用的源，则本节适用。您只能在*查看器请求* CloudFront Functions 上更新源。CloudFront Functions 有一个模块，模块提供了用于动态更新或更改源的辅助方法。

要使用此模块，请使用 JavaScript 运行时 2.0 创建 CloudFront 函数，并在函数代码的第一行包含以下语句：

```
import cf from 'cloudfront';
```

有关更多信息，请参阅 [适用于 CloudFront Functions 的 JavaScript 运行时系统 2.0 特征](functions-javascript-runtime-20.md)。

**注意**  
Test API 和 Test 控制台页面不测试是否修改了源。但是，测试可确保函数代码的执行没有错误。

## 在 CloudFront Functions 和 Lambda@Edge 之间进行选择
<a name="origin-modification-considerations"></a>

您可以使用 CloudFront Functions 或 Lambda@Edge 来更新源。

使用 CloudFront Functions 更新源时，您可以使用*查看器请求*事件触发器，这意味着使用此函数时，此逻辑将在每个请求上运行。使用 Lambda@Edge 时，源更新功能在*源请求*事件触发器上，这意味着此逻辑仅在缓存未命中时运行。

您的选择在很大程度上取决于您的工作负载以及您的分配中目前使用的是 CloudFront Functions 还是 Lambda@Edge。您可以参考注意事项，来决定使用 CloudFront Functions 还是 Lambda@Edge 更新您的源。

CloudFront Functions 在以下情况中更为有用：
+ 当您的请求是动态的（意味着无法缓存这些请求）并且将始终转向源时。CloudFront Functions 可提供更好的性能和更低的总体成本。
+ 如果您现在已有查看器请求 CloudFront 函数并将在每个请求上运行，则可以将源更新逻辑添加到现有函数中。

要使用 CloudFront Functions 更新源，请参阅以下主题中的辅助方法。

Lambda@Edge 在以下情况中更为有用：
+ 当您拥有可以很好地缓存的内容时，Lambda@Edge 更具成本效益，因为它仅在缓存未命中时运行，而 CloudFront Functions 在每次请求时都会运行。
+ 如果您现在已有查看器请求 Lambda@Edge 函数，则可以将源更新逻辑添加到现有函数中。
+ 当您的源更新逻辑需要从第三方数据来源（例如 Amazon DynamoDB 或 Amazon S3）提取数据时。

有关 Lambda@Edge 的更多信息，请参阅[使用 Lambda@Edge 在边缘进行自定义](lambda-at-the-edge.md)。

## updateRequestOrigin() 方法
<a name="update-request-origin-helper-function"></a>

使用 `updateRequestOrigin()` 方法更新请求的源设置。您可以使用此方法，更新分配中已定义源的现有源属性，或者为请求定义新的源。为此，请指定要更改的属性。

**重要**  
未在 `updateRequestOrigin()` 中指定的任何设置都将从现有源的配置继承*相同的设置*。

`updateRequestOrigin()` 方法设置的源可以是任意 HTTP 端点，并且不必是您的 CloudFront 分配中的现有源。

**备注**  
如果您要更新某个属于源组的源，则仅更新源组的*主源*。辅助源保持不变。来自已修改源的任何符合失效转移条件的响应代码都将触发到辅助源的失效转移。
如果要更改源类型并启用 OAC，请确保 `originAccessControlConfig` 中的源类型与新的源类型相匹配。
您不能使用 `updateRequestOrigin()` 方法更新 [VPC 源](private-content-vpc-origins.md)。请求将失败。

**请求**

```
updateRequestOrigin({origin properties})
```

`origin properties` 可包含以下内容：

**domainName（可选）**  
源的域名。如果未提供此信息，则改为使用分配的源的域名。    
**对于自定义源**  
指定 DNS 域名，例如 `www.example.com`。域名不能包含冒号（`:`），也不能为 IP 地址。域名最多可以有 253 个字符。  
**对于 S3 源**  
指定 Amazon S3 存储桶的 DNS 域名，例如 `amzn-s3-demo-bucket.s3.eu-west-1.amazonaws.com`。名称必须最多为 128 个字符，并且必须为全小写。

**hostHeader（可选，适用于非 S3 自定义源）**  
向源发出请求时使用的主机标头。如果未提供此值，则使用 domainName 参数中的值。如果既未提供主机标头也未提供域名参数，则使用来自分配的源的域名，或者如果转发到源（FTO）策略包括主机，则使用来自传入请求的主机标头。主机标头不能包含冒号（`:`），也不能为 IP 地址。主机标头最多可以有 253 个字符。

**originPath（可选）**  
源上的目录路径，请求应在其中查找内容。路径应该以正斜杠（/）开头，但不应该以正斜杠结尾。例如，路径结尾不能是 `example-path/`。如果未提供此信息，则使用所分配源的源路径。    
**对于自定义源**  
路径应为 URL 编码，最大长度为 255 个字符。

**customHeaders（可选）**  
您可以通过为每个自定义标头指定标头名称/值对，在请求中包括自定义标头。其格式与事件结构中请求和响应标头的格式不同。使用以下键/值对语法：  

```
{"key1": "value1", "key2": "value2", ...}
```
您不能添加不允许使用的标头，并且传入请求 `headers` 中不能存在同名标头。在函数代码中，标头名称必须为小写。当 CloudFront Functions 将事件对象转换回 HTTP 请求时，标头名称中每个单词的第一个字母都会大写，使用连字符分隔单词。  
例如，如果您的函数代码添加了名为 `example-header-name` 的标头，CloudFront 会将其转换为 HTTP 请求中的 `Example-Header-Name`。有关更多信息，请参阅[CloudFront 无法添加到源请求的自定义标头](add-origin-custom-headers.md#add-origin-custom-headers-denylist)和[边缘函数的限制](edge-functions-restrictions.md)。  
如果未提供此信息，则使用分配的源中的任意自定义标头。

**connectionAttempts（可选）**  
CloudFront 尝试连接到源的次数。最小值为 1，最大值为 3。如果未提供此信息，则使用分配的源中的连接尝试次数。

**originShield（可选）**  
此项启用或更新 CloudFront 源护盾。使用 Origin Shield 有助于减少源上的负载。有关更多信息，请参阅 [使用 Amazon CloudFront Origin Shield](origin-shield.md)。如果未提供此信息，则使用所分配源的源护盾设置。    
**enabled（必需）**  
用于启用或禁用源护盾的布尔表达式。接受的值为 `true` 或 `false`。  
**region（启用时为必需）**  
Origin Shield 的 AWS 区域。指定到源的延迟最低的 AWS 区域。使用区域代码，而不是区域名称。例如，使用 `us-east-2` 指定美国东部（俄亥俄州）区域。  
启用 CloudFront 源护盾时，您必须为其指定 AWS 区域。有关可用 AWS 区域列表以及帮助您为源选择合适区域的信息，请参阅[为 Origin Shield 选择 AWS 区域](origin-shield.md#choose-origin-shield-region)。

**originAccessControlConfig（可选）**  
此源的源访问控制（OAC，Origin Access Control）的唯一标识符。只有当源支持 CloudFront OAC（例如 Amazon S3、Lambda 函数 URL、MediaStore 和 MediaPackage V2）时，才使用此选项。如果未提供此信息，则使用分配的源的 OAC 设置。  
此项不支持传统来源访问身份（OAI）。有关更多信息，请参阅 [限制对AWS源的访问](private-content-restricting-access-to-origin.md)。    
**enabled（必需）**  
用于启用或禁用 OAC 的布尔表达式。接受的值为 `true` 或 `false`。  
**signingBehavior（启用时为必需）**  
指定 CloudFront 签署（将身份验证信息添加到）哪些请求。为最常见的使用案例指定 `always`。有关更多信息，请参阅 [源访问控制的高级设置](private-content-restricting-access-to-s3.md#oac-advanced-settings-s3)。  
此字段可能具有下列值之一：  
+ `always` - CloudFront 签署所有源请求，覆盖来自查看器请求的 `Authorization` 标头（如果存在）。
+ `never` – CloudFront 不签署任何源请求。此值将关闭源的源访问控制。
+ `no-override` – 如果查看器请求不包含 `Authorization` 标头，则 CloudFront 签署源请求。如果查看器请求包含 `Authorization` 标头，则 CloudFront 不会签署源请求，而是传递查看器请求的 `Authorization` 标头。
**警告**  
要传递查看器请求中的 `Authorization` 标头，您必须针对使用与此源访问控制关联的源的所有缓存行为，将标头添加到源请求策略中。有关更多信息，请参阅 [使用策略来控制源请求](controlling-origin-requests.md)。  
**signingProtocol（启用时为必需）**  
OAC 的签名协议，确定 CloudFront 如何签署（身份验证）请求。唯一有效值为 `sigv4`。  
**originType（启用时为必需）**  
此 OAC 的源类型。有效值包括 `s3`、`mediapackagev2`、`mediastore` 和 `lambda`。

**timeouts（可选）**  
超时值，您可以用来指定 CloudFront 尝试等待源响应或发送数据的时间。如果未提供此信息，则使用分配的源的超时设置。  
除非另有说明，否则这些超时同时支持自定义源和 Amazon S3 源。  
**readTimeout（可选）**  
`readTimeout` 适用于以下两个值：  
+ CloudFront 在将请求转发到源后等待响应的时间长度（以秒为单位）。
+ CloudFront 从收到来自源的一个响应数据包到收到下一个数据包之间等待的时间长度（以秒为单位）。
最短超时为 1 秒，最长超时为 120 秒。有关更多信息，请参阅 [响应超时](DownloadDistValuesOrigin.md#DownloadDistValuesOriginResponseTimeout)。  
**responseCompletionTimeout（可选）**  
从 CloudFront 向源发出的请求可以保持打开状态并等待响应的时间（以秒为单位）。如果此时未收到来自源的完整响应，CloudFront 将终止连接。  
`responseCompletionTimeout` 的值必须大于或等于 `readTimeout` 的值。有关更多信息，请参阅 [响应完成超时](DownloadDistValuesOrigin.md#response-completion-timeout)。  
**keepAliveTimeout（可选）**  
此超时仅适用于自定义源，而不适用于 Amazon S3 源。（S3 源配置将忽略这些设置。）   
`keepAliveTimeout` 指定 CloudFront 在收到响应的最后一个数据包后，应尝试与源保持连接的时间长度。最短超时为 1 秒，最长超时为 120 秒。有关更多信息，请参阅 [源保持连接超时（仅自定义源和 VPC 源）](DownloadDistValuesOrigin.md#DownloadDistValuesOriginKeepaliveTimeout)。  
**connectionTimeout（可选）**  
CloudFront 尝试建立与源的连接时等待的秒数。最短超时为 1 秒，最长超时为 10 秒。有关更多信息，请参阅 [连接超时](DownloadDistValuesOrigin.md#origin-connection-timeout)。

**customOriginConfig（可选）**  
使用 `customOriginConfig`，为*不是* Amazon S3 存储桶的源指定连接设置。但有一个例外：如果 S3 存储桶配置了静态网站托管，则您可以指定这些设置。（其他类型的 S3 存储桶配置将忽略这些设置。） 如果未提供 `customOriginConfig`，则使用分配的源的设置。    
**port（必需）**  
CloudFront 用于连接到源的 HTTP 端口。指定源侦听的 HTTP 端口。  
**protocol（必需）**  
指定 CloudFront 用于连接到源的协议（HTTP 或 HTTPS）。有效值如下所示：  
+ `http` – CloudFront 始终使用 HTTP 连接到源。
+ `https` – CloudFront 始终使用 HTTPS 连接到源。  
**sslProtocols（必需）**  
指定 CloudFront 在通过 HTTPS 连接到源时使用的最低 SSL/TLS 协议版本的列表。有效值包括 `SSLv3`、`TLSv1`、`TLSv1.1` 和 `TLSv1.2`。有关更多信息，请参阅 [最低限度源 SSL 协议](DownloadDistValuesOrigin.md#DownloadDistValuesOriginSSLProtocols)。  
**ipAddressType（可选）**  
指定 CloudFront 用于连接到源的 IP 地址类型。有效值包括 `ipv4`、`ipv6` 和 `dualstack`。仅当同时更改 `domainName` 属性时，才支持更改 `ipAddressType`。

**sni（可选，适用于非 S3 自定义源）**  
服务器名称指示（SNI）是传输层安全性协议（TLS）的扩展，客户端可用它在 TLS 握手过程开始时指示尝试连接到的主机名。此值应与原始服务器上的 TLS 证书中的常用名称匹配。否则，原始服务器可能会引发错误。  
如果未提供此值，则使用 `hostHeader` 参数中的值。如果未提供主机标头，则使用 `domainName` 参数中的值。  
如果既未提供主机标头也未提供域名参数，则使用来自分配的源的域名，或者如果转发到源（FTO）策略包括主机，则使用来自传入请求的主机标头。SNI 不能包含冒号（`:`），也不能为 IP 地址。SNI 最多可以有 253 个字符。

**allowedCertificateNames（可选，适用于非 S3 自定义源）**  
您可以配置一个有效证书名称列表，CloudFront 在与原始服务器进行 TLS 握手的过程中，可使用此列表来验证原始服务器 TLS 证书中的域匹配情况。此字段需传入一个有效域名数组，并且可包含通配符域，例如 `*.example.com`。  
最多可指定 20 个允许的证书名称。每个证书名称最多可包含 64 个字符。

**Example – 更新 Amazon S3 请求源**  
以下示例将查看器请求的源更改为 S3 存储桶，启用 OAC，并重置发送到源的自定义标头。  

```
cf.updateRequestOrigin({
    "domainName" : "amzn-s3-demo-bucket-in-us-east-1.s3.us-east-1.amazonaws.com",
    "originAccessControlConfig": {
        "enabled": true,
        "signingBehavior": "always",
        "signingProtocol": "sigv4",
        "originType": "s3"
    },
    // Empty object resets any header configured on the assigned origin
    "customHeaders": {}
});
```

**Example – 更新应用程序负载均衡器请求源**  
以下示例将查看器请求的源更改为应用程序负载均衡器源，并设置自定义标头和超时。  

```
cf.updateRequestOrigin({
    "domainName" : "example-1234567890.us-east-1.elb.amazonaws.com",
    "timeouts": {
        "readTimeout": 30,
        "connectionTimeout": 5
    },
    "customHeaders": {
        "x-stage": "production",
        "x-region": "us-east-1"
    }
});
```

**Example – 更新启用了源护盾的源**  
在以下示例中，分配中的源启用了源护盾。函数代码仅更新用于源的域名，忽略了所有其他可选参数。在这种情况下，由于未更新源护盾参数，源护盾仍将与修改后的源域名一起使用。  

```
cf.updateRequestOrigin({
    "domainName" : "www.example.com"
});
```

**Example ：更新主机标头、SNI 和允许的证书名称**  
对于大多数使用案例，您无需对转至源的请求进行此类修改。除非您了解更改这些值将产生的影响，否则不应使用上述参数。
以下示例将更改转至源的请求中的域名、主机标头、SNI 和允许的证书。  

```
cf.updateRequestOrigin({ 
    "domainName": "www.example.com", 
    "hostHeader": "test.example.com", 
    "sni": "test.example.net", 
    "allowedCertificateNames": ["*.example.com", "*.example.net"],
});
```

## selectRequestOriginById() 方法
<a name="select-request-origin-id-helper-function"></a>

使用 `selectRequestOriginById()` 可通过选择已在您的分配中配置的其它源来更新现有源。此方法使用由更新的源定义的所有相同设置。

此方法只接受在运行函数时使用的同一分配中已经定义的源。源由源 ID 引用，而源 ID 是您在设置源时定义的源名称。

如果您在分配中配置了 VPC 源，则可以使用此方法来将您的源更新为 VPC 源。有关更多信息，请参阅 [通过 VPC 源限制访问](private-content-vpc-origins.md)。

**备注**  
`selectRequestOriginById()` 函数无法选择已启用双向 TLS（源）的源。尝试使用此函数选择已启用双向 TLS（源）的源将导致验证错误。
如果使用案例要求使用双向 TLS（源）进行动态源选择，请改用 `updateRequestOrigin()`，确保所有目标源都使用相同的客户端证书。

**请求**

```
cf.selectRequestOriginById(origin_id, {origin_overrides})
```

在上一示例中，`origin_id` 是一个字符串，它指向运行该函数的分配中源的源名称。`origin_overrides ` 参数可包含：

**hostHeader（可选，适用于非 S3 自定义源）**  
向源发出请求时使用的主机标头。如果未提供此值，则使用 `domainName` 参数中的值。  
如果既未提供主机标头也未提供域名参数，则使用来自分配的源的域名，或者如果转发到源（FTO）策略包括主机，则使用来自传入请求的主机标头。主机标头不能包含冒号（`:`），也不能为 IP 地址。主机标头最多可以有 253 个字符。

**sni（可选，适用于非 S3 自定义源）**  
服务器名称指示（SNI）是传输层安全性协议（TLS）的扩展，客户端可用它在 TLS 握手过程开始时指示尝试连接到的主机名。此值应与原始服务器上的 TLS 证书中的常用名称匹配。否则，原始服务器可能会引发错误。  
如果未提供此值，则使用 `hostHeader` 参数中的值。如果未提供主机标头，则使用 `domainName` 参数中的值。  
如果既未提供主机标头也未提供域名参数，则使用来自分配的源的域名，或者如果转发到源（FTO）策略包括主机，则使用来自传入请求的主机标头。SNI 不能包含冒号（`:`），也不能为 IP 地址。SNI 最多可以有 253 个字符。

**allowedCertificateNames（可选，适用于非 S3 自定义源）**  
您可以配置一个有效证书名称列表，CloudFront 在与原始服务器进行 TLS 握手的过程中，可使用此列表来验证原始服务器 TLS 证书中的域匹配情况。此字段需传入一个有效域名数组，并且可包含通配符域，例如 `*.example.com`。  
最多可指定 20 个允许的证书名称。每个证书名称最多可包含 64 个字符。

**请求**

```
selectRequestOriginById(origin_id)
```

在前面的示例中，`origin_id` 是一个字符串，它指向运行该函数的分配中源的源名称。

**Example – 选择 Amazon S3 请求源**  
以下示例从与分配关联的源列表中选择名为 `amzn-s3-demo-bucket-in-us-east-1` 的源，并将 `amzn-s3-demo-bucket-in-us-east-1` 源的配置设置应用于请求。  

```
cf.selectRequestOriginById("amzn-s3-demo-bucket-in-us-east-1");
```

**Example – 选择应用程序负载均衡器请求源**  
以下示例从与分配关联的源列表中选择名为 `myALB-prod` 的应用程序负载均衡器源，并将 `myALB-prod` 的配置设置应用于请求。  

```
cf.selectRequestOriginById("myALB-prod");
```

**Example ：选择应用程序负载均衡器请求源并覆盖主机标头**  
与上一示例类似，以下示例从与分配关联的源列表中选择名为 `myALB-prod` 的应用程序负载均衡器源，并将 `myALB-prod` 的配置设置应用于请求。但是，此示例使用 `origin_overrides` 覆盖主机标头值。  

```
cf.overrideRequestOrigin("myALB-prod",{ 
        "hostHeader" : "test.example.com"
});
```

## createRequestOriginGroup() 方法
<a name="create-request-origin-group-helper-function"></a>

使用 `createRequestOriginGroup()` 可定义两个源，以便在需要高可用性的场景中用作失效转移的[源组](high_availability_origin_failover.md#concept_origin_groups.creating)。

源组包括两个源（主源和辅助源）以及您指定的失效转移条件。您可以创建一个源组以支持 CloudFront 中的源失效转移。使用此方法创建或更新源组时，您可以指定源组而不是单个源。CloudFront 将使用失效转移条件从主源失效转移到辅助源。

如果您在分配中配置了 VPC 源，则可以使用此方法通过 VPC 源创建源组。有关更多信息，请参阅 [通过 VPC 源限制访问](private-content-vpc-origins.md)。

**备注**  
`createRequestOriginGroup()` 函数不支持创建包含已启用双向 TLS（源）的源的源组。无法通过 CloudFront Functions 动态创建具有双向 TLS（源）源的源组。
如果您需要具有双向 TLS（源）的源失效转移功能，请直接在 CloudFront 分配设置中配置源组，而不是在函数中动态创建源组。

### 请求
<a name="create-origin-group-request"></a>

```
createRequestOriginGroup({origin_group_properties})
```

在前面的示例中，`origin_group_properties` 文件包含以下内容：

**originIds（必需）**  
`origin_ids` 的数组，其中 `origin_id` 是一个字符串，它指向运行该函数的分配中源的源名称。您必须提供两个源来作为数组的一部分。列表中的第一个源是主源，而第二个源用作用于进行失效转移的辅助源。

**originOverrides（可选）**  
 有几个高级设置可以使用 `{origin_overrides}` 参数进行覆盖。`origin overrides` 可包含以下内容：    
**hostHeader（可选，适用于非 S3 自定义源）**  
向源发出请求时使用的主机标头。如果未提供此值，则使用 `domainName` 参数中的值。  
如果既未提供主机标头也未提供域名参数，则使用来自分配的源的域名，或者如果转发到源（FTO）策略包括主机，则使用来自传入请求的主机标头。主机标头不能包含冒号（`:`），也不能为 IP 地址。主机标头最多可以有 253 个字符。  
**sni（可选，适用于非 S3 自定义源）**  
服务器名称指示（SNI）是传输层安全性协议（TLS）的扩展，客户端可用它在 TLS 握手过程开始时指示尝试连接到的主机名。此值应与原始服务器上的 TLS 证书中的常用名称匹配，否则原始服务器可能会引发错误。  
如果未提供此值，则使用 `hostHeader` 参数中的值。如果未提供主机标头，则使用 `domainName` 参数中的值。  
如果既未提供主机标头也未提供域名参数，则使用来自分配的源的域名，或者如果转发到源（FTO）策略包括主机，则使用来自传入请求的主机标头。SNI 不能包含冒号（`:`），也不能为 IP 地址。SNI 最多可以有 253 个字符。  
**allowedCertificateNames（可选，适用于非 S3 自定义源）**  
您可以配置一个有效证书名称列表，CloudFront 在与原始服务器进行 TLS 握手的过程中，可使用此列表来验证原始服务器 TLS 证书中的域匹配情况。此字段需传入一个有效域名数组，并且可包含通配符域，例如 `*.example.com`。  
最多可指定 20 个允许的证书名称。每个证书名称最多可包含 64 个字符。

**selectionCriteria（可选）**  
选择是使用 `default` 源失效转移条件，还是使用基于 `media-quality-score` 的失效转移逻辑。有效值如下所示：  
+ `default` 根据在 `failoverCriteria` 中指定的状态代码，使用失效转移条件。如果您未在函数中设置 `selectionCriteria`，将使用 `default`。
+ 当使用媒体感知路由功能时，使用 `media-quality-score`。

**failoverCriteria（必需）**  
从主源返回时，将触发 CloudFront 失效转移到辅助源的状态代码数组。如果您覆盖现有的源组，此数组将覆盖在源组的原始配置中设置的所有失效转移状态代码。  
当您使用 `media-quality-score` `selectionCriteria` 时，CloudFront 将尝试根据媒体质量分数来路由请求。如果所选源返回在此数组中设置的错误代码，则 CloudFront 将失效转移到另一个源。

**Example – 创建请求源组**  
以下示例使用源 ID 为请求创建源组。这些源 ID 来自用于运行此函数的分配的源组配置。  
（可选）您可以使用 `originOverrides` 覆盖 `sni`、`hostHeader` 和 `allowedCertificateNames` 的源组配置。  

```
import cf from 'cloudfront';

function handler(event) {
    cf.createRequestOriginGroup({
        "originIds": [
            {
                "originId": "origin-1",
                "originOverrides": {
                    "hostHeader": "hostHeader.example.com",
                    "sni": "sni.example.com",
                    "allowedCertificateNames": ["cert1.example.com", "cert2.example.com", "cert3.example.com"]
                }
            },
            {
                "originId": "origin-2",
                "originOverrides": {
                    "hostHeader": "hostHeader2.example.com",
                    "sni": "sni2.example.com",
                    "allowedCertificateNames": ["cert4.example.com", "cert5.example.com"]
                }
            }
        ],
        "failoverCriteria": {
            "statusCodes": [500]
        }
    });
    
    event.request.headers['x-hookx'] = { value: 'origin-overrides' };
    return event.request;
}
```

# CloudFront SaaS Manager 属性的辅助方法
<a name="saas-specific-logic-function-code"></a>

使用以下适用于 CloudFront SaaS Manager 的辅助函数，在您创建的函数中检索多租户分配的值。要使用此页上的示例，您必须先使用 JavaScript 运行时 2.0 创建 CloudFront 函数。有关更多信息，请参阅 [适用于 CloudFront Functions 的 JavaScript 运行时系统 2.0 特征](functions-javascript-runtime-20.md)。

**Topics**
+ [

## 连接组
](#connection-groups-helper-function)
+ [

## 分配租户
](#distribution-tenants-helper-functions)

## 连接组
<a name="connection-groups-helper-function"></a>

与分配租户关联的连接组具有域名。

要获取此值，请使用事件对象的 `context` 子对象的 `endpoint` 字段。

**请求**

```
const value = event.context.endpoint;
```

**响应**

响应是一个包含连接组域名的 `string`，例如 d111111abcdef8.cloudfront.net。`endpoint` 字段仅在针对具有关联连接组的多租户分配调用您的函数时才会出现。有关更多信息，请参阅 [Context 对象](functions-event-structure.md#functions-event-structure-context)。

## 分配租户
<a name="distribution-tenants-helper-functions"></a>

CloudFront Functions 有一个模块，该模块提供对特定分配租户值的访问权限。

要使用此模块，请在函数代码的第一行中包含以下语句：

```
import cf from 'cloudfront';
```

您只能在 `handler` 函数中使用以下示例，可以直接使用，也可以通过任何嵌套调用函数来使用。

### `distributionTenant.id`字段
<a name="distribution-tenants-field"></a>

使用此字段可获取分配租户 ID 的值。

**请求**

```
const value = cf.distributionTenant.id;
```

**响应**

响应是包含分配租户 ID 的 `string`，例如 `dt_1a2b3c4d5e6f7`。

**错误处理**

如果针对标准分配调用您的函数，则指定 `distributionTenant.id` 字段将返回 `distributionTenant module is not available` 类型错误。要处理此用例，您可以向代码中添加 `try` 和 `catch` 块。

### `distributionTenant.parameters.get()` 方法
<a name="distribution-tenant-parameters-get-method"></a>

使用此方法可返回您指定的分配租户参数名称的值。

```
distributionTenant.parameters.get("key");
```

`key`：您要获取其值的分配租户参数名称。

**请求**

```
const value = distributionTenant.parameters.get("key");
```

**响应**

响应是包含分配租户参数的值的 `string`。例如，如果您的键名称是 `TenantPath`，则此参数的值可能是 `tenant1`。

**错误处理**

您可能会收到以下错误：
+ 如果针对标准分配调用您的函数，则 `distributionTenant.parameters.get()` 方法将返回 `distributionTenant module is not available` 类型错误。
+ 当您指定的分配租户参数不存在时，将返回 `DistributionTenantParameterKeyNotFound` 错误。

要管理这些用例，您可以向代码中添加 `try` 和 `catch` 块。

# 使用 async 和 await
<a name="async-await-syntax"></a>

CloudFront Functions JavaScript 运行时函数 2.0 提供了 `async` 和 `await` 语法来处理 `Promise` 对象。Promise 表示延迟的结果，可以通过标记为 `async` 的函数中的 `await` 关键字进行访问。各种新的 WebCrypto 函数都使用 Promise。

有关 `Promise` 对象的更多信息，请参阅 [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)。

**注意**  
对于以下代码示例，您必须使用 JavaScript 运行时 2.0。  
`await` 只能在 `async` 函数内部使用。不支持 `async` 参数和闭包。

```
async function answer() {
    return 42;
}

// Note: async, await can be used only inside an async function. async arguments and closures are not supported.

async function handler(event) {
    // var answer_value = answer(); // returns Promise, not a 42 value
    let answer_value = await answer(); // resolves Promise, 42
    console.log("Answer"+answer_value);
    event.request.headers['answer'] = { value : ""+answer_value };
    return event.request;
}
```

以下 JavaScript 代码示例演示了如何使用 `then` 链式方法查看 Promise。您可以使用 `catch` 来查看错误。

**警告**  
使用 Promise 组合器（例如 `Promise.all`、`Promise.any`）和 Promise 链方法（例如 `then` 和 `catch`）可能需要大量的函数内存使用量。如果您的函数超过了[最大函数内存](cloudfront-limits.md#limits-functions)配额，它将无法执行。为避免出现此错误，建议您使用 `await` 语法，而不是 `promise` 方法。

```
async function answer() {
    return 42;
}

async function squared_answer() {
   return answer().then(value => value * value)
} 
// Note: async, await can be used only inside an async function. async arguments and closures are not supported.
async function handler(event) {
    // var answer_value = answer(); // returns Promise, not a 42 value
    let answer_value = await squared_answer(); // resolves Promise, 42
    console.log("Answer"+answer_value);
    event.request.headers['answer'] = { value : ""+answer_value };
    return event.request;
}
```

# CloudFront Functions 中的 CWT 支持
<a name="cwt-support-cloudfront-functions"></a>

此部分详细介绍 CloudFront Functions 中的 CBOR Web 令牌（CWT）支持功能，可使用该功能在 CloudFront 边缘站点实施基于令牌的安全身份验证和授权。此支持功能以模块形式提供，可通过 CloudFront 函数访问。

要使用此模块，请使用 JavaScript 运行时 2.0 创建 CloudFront 函数，并在函数代码的第一行包含以下语句：

```
import cf from 'cloudfront';
```

可通过以下方式访问与此模块关联的方法（其中，\$1 是表示模块中存在的不同函数的通配符）：

```
cf.cwt.*
```

有关更多信息，请参阅[适用于 CloudFront Functions 的 JavaScript 运行时系统 2.0 特征](functions-javascript-runtime-20.md)。

目前，此模块仅支持采用 HS256（HMAC-SHA256）算法的 MAC0 结构，最大令牌大小的限制为 1 KB。

## 令牌结构
<a name="token-structure"></a>

此部分介绍 CWT 模块所需的令牌结构。该模块要求令牌必须带有正确的标签且可识别（例如，COSE MAC0）。此外，在令牌结构方面，该模块遵循 [CBOR 对象签名与加密（COSE）[RFC 8152]](https://datatracker.ietf.org/doc/html/rfc8152) 设定的标准。

```
( // CWT Tag (Tag value: 61) --- optional    
    ( // COSE MAC0 Structure Tag (Tag value: 17) --- required        
        [            
            protectedHeaders,            
            unprotectedHeaders,            
            payload,            
            tag,        
        ]    
    )
)
```

**Example ：使用 COSE MAC0 结构的 CWT**  

```
61( // CWT tag     
    17( // COSE_MAC0 tag       
        [         
            { // Protected Headers           
                1: 4  // algorithm : HMAC-256-64         
            },         
            { // Unprotected Headers           
                4: h'53796d6d6574726963323536' // kid : Symmetric key id          
            },         
            { // Payload           
                1: "https://iss.example.com", // iss           
                2: "exampleUser", // sub           
                3: "https://aud.example.com", // aud           
                4: 1444064944, // exp           
                5: 1443944944, // nbf           
                6: 1443944944, // iat         
            },         
            h'093101ef6d789200' // tag       
        ]     
    )   
)
```
生成令牌时，CWT 标签是可选的。不过，COSE 结构标签是必需的。

## validateToken() 方法
<a name="validatetoken-method"></a>

该函数使用指定密钥对 CWT 令牌进行解码和验证。如果验证成功，则将返回已解码的 CWT 令牌。否则，将引发错误。请注意，该函数不执行任何声明集验证操作。

### 请求
<a name="validatetoken-request"></a>

```
cf.cwt.validateToken(token, handlerContext{key})
```参数

**token（必需）**  
用于验证的编码令牌。这必须是 JavaScript 缓冲区。

**handlerContext（必需）**  
一个 JavaScript 对象，用于存储 validateToken 调用的上下文。目前，仅支持 key 属性。

**key（必需）**  
用于消息摘要计算的私密密钥。可以字符串或 JavaScript 缓冲区的形式提供。

### 响应
<a name="validatetoken-response"></a>

当 `validateToken()` 方法返回成功验证的令牌时，来自函数的响应将为采用以下格式的 `CWTObject`。解码后，所有声明密钥都以字符串形式表示。

```
CWTObject {    
    protectedHeaders,    
    unprotectedHeaders,    
    payload
}
```

### 示例：使用作为令牌一部分发送的 kid 验证令牌
<a name="validatetoken-example"></a>

此示例演示了 CWT 令牌验证过程，其中会从标头中提取 kid。之后，将 kid 传入 CloudFront Functions KeyValueStore 中，以提取用于验证令牌的私密密钥。

```
import cf from 'cloudfront'

const CwtClaims = {
   iss: 1,
   aud: 3,
   exp: 4
}

async function handler(event) {
    try {
        let request = event.request;
        let encodedToken = request.headers['x-cwt-token'].value;
        let kid = request.headers['x-cwt-kid'].value;
                
        // Retrieve the secret key from the kvs
        let secretKey = await cf.kvs().get(kid);
                 
        // Now you can use the secretKey to decode & validate the token.
        let tokenBuffer = Buffer.from(encodedToken, 'base64url');
                
        let handlerContext = {
           key: secretKey,
        }
                
        try {
            let cwtObj = cf.cwt.validateToken(tokenBuffer, handlerContext);
                        
            // Check if token is expired
            const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
            if (cwtObj[CwtClaims.exp] && cwtObj[CwtClaims.exp] < currentTime) {
                return {
                    statusCode: 401,
                    statusDescription: 'Token expired'
                };
            }
        } catch (error) {
            return {
               statusCode: 401,
               statusDescription: 'Invalid token'
            };
         }
    } catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
     }
    return request;
}
```

## generateToken() 方法
<a name="generatetoken-method"></a>

此函数使用提供的有效载荷和上下文设置来生成新的 CWT 令牌。

### 请求
<a name="generatetoken-request"></a>

```
cf.cwt.generateToken(generatorContext, payload)
```参数

**generatorContext（必需）**  
这是一个 JavaScript 对象，用作生成令牌的上下文且包含以下键值对：    
**cwtTag（可选）**  
此值是一个布尔值，如果为 `true`，则指定应添加 `cwtTag`。  
**coseTag（必需）**  
指定 COSE 标签类型。目前仅支持 `MAC0`。  
**key（必需）**  
用于计算消息摘要的私密密钥。此值可以是字符串或 JavaScript `Buffer`。

**payload（必需）**  
用于编码的令牌有效载荷。有效载荷必须采用 `CWTObject` 格式。

### 响应
<a name="generatetoken-response"></a>

返回包含已编码的令牌的 JavaScript 缓冲区。

**Example ：生成 CWT 令牌**  

```
import cf from 'cloudfront';

const CwtClaims = {
    iss: 1,
    sub: 2,
    exp: 4
};

const CatClaims = {
    catu: 401,
    catnip: 402,
    catm: 403,
    catr: 404
};

const Catu = {
    host: 1,
    path: 2,
    ext: 3
};

const CatuMatchTypes = {
    prefix_match: 1,
    suffix_match: 2,
    exact_match: 3
};

const Catr = {
    renewal_method: 1,
    next_renewal_time: 2,
    max_uses: 3
};

async function handler(event) {
    try {
        const response = {
            statusCode: 200,
            statusDescription: 'OK',
            headers: {}
        };
        
        const commonAccessToken = {
            protected: {
                1: "5",
            },
            unprotected: {},
            payload: {
                [CwtClaims.iss]: "cloudfront-documentation",
                [CwtClaims.sub]: "cwt-support-on-cloudfront-functions",
                [CwtClaims.exp]: 1740000000,
                [CatClaims.catu]: {
                    [Catu.host]: {
                        [CatuMatchTypes.suffix_match]: ".cloudfront.net"
                    },
                    [Catu.path]: {
                        [CatuMatchTypes.prefix_match]: "/media/live-stream/cf-4k/"
                    },
                    [Catu.ext]: {
                        [CatuMatchTypes.exact_match]: [
                            ".m3u8",
                            ".ts",
                            ".mpd"
                        ]
                    }
                },
                [CatClaims.catnip]: [
                    "[IP_ADDRESS]",
                    "[IP_ADDRESS]"
                ],
                [CatClaims.catm]: [
                    "GET",
                    "HEAD"
                ],
                [CatClaims.catr]: {
                    [Catr.renewal_method]: "header_renewal",
                    [Catr.next_renewal_time]: 1750000000,
                    [Catr.max_uses]: 5
                }
            }
        };
        
        if (!request.headers['x-cwt-kid']) {
            throw new Error('Missing x-cwt-kid header');
        }
        
        const kid = request.headers['x-cwt-kid'].value;
        const secretKey = await cf.kvs().get(kid);
        
        if (!secretKey) {
            throw new Error('Secret key not found for provided kid');
        }
        
        try {
            const genContext = {
                cwtTag: true,
                coseTag: "MAC0",
                key: secretKey
            };
            
            const tokenBuffer = cf.cwt.generateToken(commonAccessToken, genContext);
            response.headers['x-generated-cwt-token'] = { value: tokenBuffer.toString('base64url') };
                        
            return response;
        } catch (tokenError) {
            return {
                statusCode: 401,
                statusDescription: 'Could not generate the token'
            };
        }
    } catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
    }
}
```

**Example ：根据某种逻辑刷新令牌**  

```
import cf from 'cloudfront'

const CwtClaims = {
   iss: 1,
   aud: 3,
   exp: 4
}

async function handler(event) {
    try {
        let request = event.request;
        let encodedToken = request.headers['x-cwt-token'].value;
        let kid = request.headers['x-cwt-kid'].value;
        let secretKey = await cf.kvs().get(kid); // Retrieve the secret key from the kvs
                
        // Now you can use the secretKey to decode & validate the token.
        let tokenBuffer = Buffer.from(encodedToken, 'base64url');
                
        let handlerContext = {
           key: secretKey,
        }
                
        try {
            let cwtJSON = cf.cwt.validateToken(tokenBuffer, handlerContext);
                        
            // Check if token is expired
            const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
            if (cwtJSON[CwtClaims.exp] && cwtJSON[CwtClaims.exp] < currentTime) {
                // We can regnerate the token and add 8 hours to the expiry time
                cwtJSON[CwtClaims.exp] = Math.floor(Date.now() / 1000) + (8 * 60 * 60);
                                
                let genContext = {
                  coseTag: "MAC0",
                  key: secretKey
                }
                                
                let newTokenBuffer = cf.cwt.generateToken(cwtJSON, genContext);
                 request.headers['x-cwt-regenerated-token'] = newTokenBuffer.toString('base64url');
            }
        } catch (error) {
            return {
               statusCode: 401,
               statusDescription: 'Invalid token'
            };
         }
    }
    catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
     }
    return request;
}
```

# 通用辅助方法
<a name="general-helper-methods"></a>

本页面提供了 CloudFront Functions 中的其他辅助方法。要使用这些方法，请使用 JavaScript 运行时 2.0 创建 CloudFront 函数。

```
import cf from 'cloudfront';
```

有关更多信息，请参阅[适用于 CloudFront Functions 的 JavaScript 运行时系统 2.0 特征](functions-javascript-runtime-20.md)。

## `edgeLocation` 元数据
<a name="edge-location-metadata"></a>

此方法需要使用 `cloudfront` 模块。

**注意**  
您只能将此方法用于查看器-请求函数。对于查看器-响应函数，此方法为空。

使用此 JavaScript 对象可获取边缘站点机场代码、预期的[区域边缘缓存](HowCloudFrontWorks.md#CloudFrontRegionaledgecaches)区域，或用于处理请求的 CloudFront 服务器 IP 地址。此元数据仅在查看器请求事件触发时可用。

```
cf.edgeLocation = {
    name: SEA
    serverIp: 1.2.3.4
    region: us-west-2
}
```

`cf.edgeLocation` 对象可包含：

**name**  
处理请求的边缘站点的三字母 [IATA 代码](https://en.wikipedia.org/wiki/IATA_airport_code)。

**serverIp**  
处理请求的服务器的 IPv4 或 IPv6 地址。

**region**  
发生缓存未命中时请求*预计*会使用的 CloudFront 区域边缘缓存（REC）。如果预期的 REC 不可用且请求使用备用 REC，则不会更新此值。这不包括正在使用的源护盾位置，除非主 REC 和源护盾的位置相同。

**注意**  
如果 CloudFront 已配置为使用源失效转移，则不会再次调用 CloudFront Functions。有关更多信息，请参阅[通过 CloudFront 源失效转移来优化高可用性](high_availability_origin_failover.md)。

## `rawQueryString()` 方法
<a name="raw-query-string-method"></a>

此方法不需要 `cloudFront` 模块。

使用 `rawQueryString()` 方法可以字符串形式检索未解析和未更改的查询字符串。

**请求**

```
function handler(event) {
    var request = event.request;
    const qs = request.rawQueryString();
}
```

**响应**

以不带前导 `?` 的字符串值形式返回传入请求的完整查询字符串。
+ 如果没有查询字符串，但存在 `?`，则函数将返回一个空字符串。
+ 如果没有查询字符串且 `?` 不存在，则函数将返回 `undefined`。

**场景 1：返回完整查询字符串（不带前导 `?`）**  
传入请求 URL：`https://example.com/page?name=John&age=25&city=Boston`  
`rawQueryString()` 返回：`"name=John&age=25&city=Boston"`

**场景 2：返回空字符串（当 `?` 存在但没有参数时）**  
传入请求 URL：`https://example.com/page?`  
`rawQueryString()` 返回：`""`

**场景 3：返回 `undefined`（无查询字符串和 `?`）**  
传入请求 URL：`https://example.com/page`  
`rawQueryString()` 返回：`undefined`