

# 源修改的辅助方法
<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;
}
```