

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 CloudFront Functions 在邊緣進行自訂
<a name="cloudfront-functions"></a>

使用 CloudFront Functions，您可以在 JavaScript 中撰寫輕量型函數，以進行高擴展性、延遲敏感的 CDN 自訂。您的函數可以操作流經 CloudFront 的請求和回應，執行基本身分驗證和授權，在邊緣產生 HTTP 回應等。CloudFront Functions 執行時間環境提供低於一毫秒的啟動時間，可立即擴展以每秒處理數百萬個要求，並且非常安全。CloudFront Functions 是 CloudFront 的原生功能，這表示您可以在 CloudFront 中完全建置、測試和部署程式碼。

當您將 CloudFront 函式與 CloudFront 分佈建立關聯時，CloudFront 會在 CloudFront 邊緣位置攔截請求和回應，並將它們傳遞給您的函數。發生下列事件時，您可以調用 CloudFront 函數：
+ 當 CloudFront 接收到來自檢視器的請求 (檢視器請求) 時
+ 在 CloudFront 傳回回應給檢視器 (檢視器回應) 之前
+ 在建立 TLS 連線 （連線請求） 期間 - 目前可用於交互 TLS (mTLS) 連線

如需 CloudFront Functions 的詳細資訊，請參閱下列主題：

**Topics**
+ [教學課程：使用 CloudFront Functions 建立簡單的函數](functions-tutorial.md)
+ [教學課程：建立包含鍵值的 CloudFront 函數](functions-tutorial-kvs.md)
+ [撰寫函數程式碼](writing-function-code.md)
+ [建立函數](create-function.md)
+ [測試函數](test-function.md)
+ [更新函數](update-function.md)
+ [發佈函數](publish-function.md)
+ [將函數與分佈相關聯](associate-function.md)
+ [Amazon CloudFront KeyValueStore](kvs-with-functions.md)

# 教學課程：使用 CloudFront Functions 建立簡單的函數
<a name="functions-tutorial"></a>

本教學課程將協助您開始使用 CloudFront Functions。您可建立簡單函數將檢視器重新導向至不同的 URL，此外也會傳回自訂回應標頭。

**Contents**
+ [先決條件](#functions-tutorial-prerequisites)
+ [建立函數](#functions-tutorial-create)
+ [驗證函數](#functions-tutorial-verify)

## 先決條件
<a name="functions-tutorial-prerequisites"></a>

要使用 CloudFront Functions，您需要一個 CloudFront 分佈。如果您沒有帳戶，請參閱 [開始使用 CloudFront 標準分佈](GettingStarted.SimpleDistribution.md)。

## 建立函數
<a name="functions-tutorial-create"></a>

您可使用 CloudFront 主控台建立簡單函數，該函數將檢視器重新導向至不同的 URL，以及傳回自訂回應標頭。

**建立 CloudFront 函數**

1. 登入 AWS 管理主控台 ，並在 開啟 CloudFront 主控台[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)。

1. 在導覽面板上選擇**函數**，然後選擇**建立函數**。

1. 在**建立函數**頁面對**名稱**輸入函數名稱，例如 *MyFunctionName*。

1. (選用) 對於**說明**，請輸入函數的說明內容，例如 **Simple test function**。

1. 對於**執行時期**，請保留預設選取的 JavaScript 版本。

1. 選擇**建立函數**。

1. 複製下列函數程式碼。此函數程式碼會將檢視者重新導向至不同的 URL，並傳回自訂回應標頭。

   ```
   function handler(event) {
       // NOTE: This example function is for a viewer request event trigger. 
       // Choose viewer request for event trigger when you associate this function with a distribution. 
       var response = {
           statusCode: 302,
           statusDescription: 'Found',
           headers: {
               'cloudfront-functions': { value: 'generated-by-CloudFront-Functions' },
               'location': { value: 'https://aws.amazon.com/cloudfront/' }
           }
       };
       return response;
   }
   ```

1. 對於**函數程式碼**，請將程式碼貼到程式碼編輯器中，以取代預設程式碼。

1. 選擇**儲存變更**。

1. (選用) 您可以在發佈之前測試函數。本教學課程不會介紹如何測試函數。如需詳細資訊，請參閱[測試函數](test-function.md)。

1. 選擇**發佈**索引標籤，然後選擇**發佈函數**。您*必須*先發佈該函數，才能將其與 CloudFront 分佈建立關聯。

1. 接下來您可以將函數與分佈或快取行為建立關聯。在 *MyFunctionName* 頁面選擇**發佈**索引標籤。
**警告**  
在下列步驟中，選擇用於測試的分佈或快取行為。請勿將此測試函數與正式作業環境中使用的分佈或快取行為建立關聯。

1. 選擇 **Add association (建立關聯)**。

1. 在**關聯**對話方塊中，選擇分佈和/或快取行為。對於**事件類型**，請保留預設值。

1. 選擇 **Add association (建立關聯)**。

   **關聯的分佈**資料表中會顯示關聯的分佈。

1. 等待幾分鐘，讓關聯的分佈完成部署。若要檢查分佈狀態，請在**關聯的分佈**資料表中選取分佈，然後選擇**檢視分佈**。

   當分佈的狀態為**已部署**時，您就可以確認該函數正常運作。

## 驗證函數
<a name="functions-tutorial-verify"></a>

您部署函數之後，可以驗證該函數是否為您的分佈發揮作用。

**驗證函數**

1. 在 Web 瀏覽器中，導覽至分佈的網域名稱 (例如 `https://d111111abcdef8.cloudfront.net`)。

   該函數傳回重定向到瀏覽器，因此瀏覽器會自動轉到 `https://aws.amazon.com/cloudfront/`。

1. 您可在命令列視窗中使用 **curl** 之類的工具，將請求傳送至分佈的網域名稱。

   ```
   curl -v https://d111111abcdef8.cloudfront.net/
   ```

   您在回應中會看到重新導向回應 (`302 Found`) 和函數新增的自訂回應標頭。以下範例為可能的回應形式。  
**Example**  

   ```
   curl -v https://d111111abcdef8.cloudfront.net/
   > GET / HTTP/1.1
   > Host: d111111abcdef8.cloudfront.net
   > User-Agent: curl/7.64.1
   > Accept: */*
   >
   < HTTP/1.1 302 Found
   < Server: CloudFront
   < Date: Tue, 16 Mar 2021 18:50:48 GMT
   < Content-Length: 0
   < Connection: keep-alive
   < Location: https://aws.amazon.com/cloudfront/
   < Cloudfront-Functions: generated-by-CloudFront-Functions
   < X-Cache: FunctionGeneratedResponse from cloudfront
   < Via: 1.1 3035b31bddaf14eded329f8d22cf188c.cloudfront.net (CloudFront)
   < X-Amz-Cf-Pop: PHX50-C2
   < X-Amz-Cf-Id: ULZdIz6j43uGBlXyob_JctF9x7CCbwpNniiMlmNbmwzH1YWP9FsEHg==
   ```

# 教學課程：建立包含鍵值的 CloudFront 函數
<a name="functions-tutorial-kvs"></a>

本教學課程說明如何使用 CloudFront 函數納入鍵值。鍵值是鍵值對的一部分。您可以在函數程式碼中包含名稱 (來自鍵值對)。函數執行時，CloudFront 會以值取代該名稱。

鍵值對是存放在鍵值存放區中的變數。當您在函數中使用鍵 (而不是硬式編碼值) 時，您的函數會更靈活。您可以變更鍵的值，而不需要部署程式碼變更。鍵值對也可以減少函數的大小。如需詳細資訊，請參閱[Amazon CloudFront KeyValueStore](kvs-with-functions.md)。

**Contents**
+ [先決條件](#functions-kvs-tutorial-prerequisites)
+ [建立鍵值存放區](#functions-kvs-tutorial-kvs-step)
+ [將鍵值對新增到存放區](#add-key-value-pairs-to-store)
+ [建立鍵值存放區與函數的關聯](#functions-kvs-tutorial-functions-step)
+ [測試並發佈函數程式碼](#test-and-publish-function-code)

## 先決條件
<a name="functions-kvs-tutorial-prerequisites"></a>

如果您是初次使用 CloudFront Functions 函數和鍵值存放區，建議您遵循 [教學課程：使用 CloudFront Functions 建立簡單的函數](functions-tutorial.md) 中的教學課程。

完成該教學課程後，您可以遵循本教學課程來延伸您建立的函數。在本教學課程中，建議您先建立鍵值存放區。

## 建立鍵值存放區
<a name="functions-kvs-tutorial-kvs-step"></a>

首先請建立用於函數的鍵值存放區。

**建立鍵值存放區**

1. 規劃您要包含在函數中的鍵值對。請記下這些鍵的名稱。您要在函數中使用的所有鍵值對都必須位於單一鍵值存放區中。

1. 決定工作的順序。有兩種方式可以繼續：
   + 建立一個鍵值存放區，並將鍵值對新增到存放區中。然後建立 (或修改) 函數並加入鍵的名稱。
   + 或者，建立 (或修改) 函數，並加入您要使用的鍵的名稱。然後建立一個鍵值存放區，並新增鍵值對。

1. 登入 AWS 管理主控台 ，並在 開啟 CloudFront 主控台[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)。

1. 在導覽視窗中選擇**函數**，然後選擇 **KeyValueStores** 索引標籤。

1. 選擇**建立 KeyValueStore** 並輸入下列欄位：
   + 輸入存放區的名稱及 (選用) 說明。
   + 將 **S3 URI** 保留空白。在本教學課程中，您將手動輸入鍵/值對。

1. 選擇**建立**。此時會顯示新鍵值存放區的詳細資訊頁面。此頁面包含目前空白的**鍵值對**區段。

## 將鍵值對新增到存放區
<a name="add-key-value-pairs-to-store"></a>

接著手動將鍵值對清單新增至您先前建立的鍵值存放區。

**將鍵值對新增到鍵值存放區**

1. 在**鍵值對**區段中選擇**新增鍵值對**。

1. 選擇**新增配對**，然後輸入鍵和值。選擇核取記號以確認您的變更，然後重複此步驟以新增更多鍵值對。

1. 完成後請選擇**儲存變更**，以儲存在鍵值存放區中的所有鍵值對。在確認對話上選擇**完成**。

您現在有一個包含一組鍵值對的鍵值存放區。



## 建立鍵值存放區與函數的關聯
<a name="functions-kvs-tutorial-functions-step"></a>

您現在已建立鍵值存放區。並且您已經建立或修改了一個函數，其中包含鍵值存放區中的鍵名稱。您現在可以建立鍵值存放區與函數的關聯。您從函數內建立該關聯。

**建立函數與鍵值存放區的關聯**

1. 在導覽視窗中，選擇**函數**。依據預設，**函數**索引標籤會顯示在頂端。

1. 選擇函數名稱，並在**關聯的 KeyValueStore** 區段中選擇**關聯現有 KeyValueStore**。

1. 選取鍵值存放區，然後選擇**關聯 KeyValueStore**。

**注意**  
每個函數只能與一個鍵值存放區建立關聯。

## 測試並發佈函數程式碼
<a name="test-and-publish-function-code"></a>

將鍵值存放區與函數建立關聯後，您可以測試和發佈函數程式碼。每次修改函數程式碼時，應一律對其進行測試，包括執行以下操作時：
+ 將鍵值存放區與函數建立關聯。
+ 修改函數及其鍵值存放區，以包含新的鍵值對。
+ 變更鍵值對的值。

**測試並發佈函數程式碼**

1. 如需有關如何測試函數的詳細資訊，請參閱 [測試函數](test-function.md)。確定您選擇在 `DEVELOPMENT` 階段測試函數。

1. 您準備好在 `LIVE` 環境中使用函數 (搭配新的或修訂的鍵值對) 時，請發佈該函數。

   當您發佈時，CloudFront 會將函數的版本從 `DEVELOPMENT` 階段複製到即時階段。該函數具有新程式碼，並與鍵值存放區相關聯。(在即時階段無需再次執行關聯。)

   如需有關如何發佈函數的詳細資訊，請參閱 [發佈函數](publish-function.md)。

# 撰寫函數程式碼
<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 方法](helper-functions-origin-modification.md)
+ [CloudFront SaaS Manager 屬性的 helper 方法](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 回應，無論該回應來自 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 函數類型，可提供自訂驗證和身分驗證邏輯。連線函數目前可用於交互 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` 物件時，您可以省略 `distributionDomainName` 物件中的 `distributionId`、`requestId` 和 `context` 欄位。此外，請確保標頭名稱為小寫，CloudFront Functions 在生產期間傳遞給函數的 `event` 物件中也會始終採用此形式。

以下是此事件物件結構的概觀。

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

如需詳細資訊，請參閱下列主題：

**Topics**
+ [版本欄位](#functions-event-structure-version)
+ [內容物件](#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`。

## 內容物件
<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`**  
代表請求 (`Cookie` 標頭) 中 Cookie 的物件。  
`cookies` 物件針對請求中的每個 Cookie 包含一個欄位。

如需有關查詢字串、標頭和 Cookie 結構的詳細資訊，請參閱 [查詢字串、標頭和 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 Functions 將事件物件轉換回 HTTP 回應時，標頭名稱中每個單字的第一個字母會大寫。單字以連字號分隔 (`-`)。例如，如果函數程式碼新增名為 `example-header-name` 的標頭，CloudFront 會將其轉換為 HTTP 回應中的 `Example-Header-Name`。

**`cookies`**  
代表回應 (`Set-Cookie` 標頭) 中 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)。

如需有關標頭和 Cookie 結構的詳細資訊，請參閱 [查詢字串、標頭和 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 Function 將無法執行。如需更多資訊，請參閱[對所有邊緣函數的限制](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 Function 設定為傳回 400 或更高的 HTTP 錯誤，您的檢視者將不會看到您為相同狀態碼指定的[自訂錯誤頁面](creating-custom-error-pages.md)。

## 查詢字串、標頭和 Cookie 的結構
<a name="functions-event-structure-query-header-cookie"></a>

查詢字串、標頭和 Cookie 共用相同的結構。查詢字串可能會出現在請求中。標頭會出現在請求和回應中。Cookie 會出現在請求和回應中。

每個查詢字串、標頭或 Cookie 都是父系 `querystring`、`headers` 或 `cookies` 物件中的唯一欄位。欄位名稱是查詢字串、標頭或 Cookie 的名稱。每個欄位都包含具有查詢字串、標頭或 Cookie 值的 `value` 屬性。

**Contents**
+ [查詢字串值或查詢字串物件](#functions-event-structure-query)
+ [標頭的特殊考量](#functions-event-structure-headers)
+ [重複的查詢字串、標頭和 Cookie (`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 Functions 將事件物件轉換回 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'};
```

### 重複的查詢字串、標頭和 Cookie (`multiValue` 陣列)
<a name="functions-event-structure-multivalue"></a>

HTTP 請求或回應可以包含多個具有相同名稱的查詢字串、標頭或 Cookie。在此情況下，重複的查詢字串、標頭或 Cookie 會折疊成 `request` 或 `response` 物件中的一個欄位，但此欄位包含一個名為 `multiValue` 的額外屬性。`multiValue` 屬性包含一個陣列，其中帶有每個重複查詢字串、標頭或 Cookie 的值。

**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 到 12 的一些功能。

我們建議您使用 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 剩餘參數語法。

**Unicode**  
來源文字和字串常值可以包含 Unicode 編碼的字元。也支援由六個字元 (例如 `\uXXXX`) 組成的 Unicode 字碼指標逸出序列。

**嚴格模式**  
函數按預設會在嚴格模式下運作，因此您不需要在函數程式碼中新增 `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`。

**Array**  
支援陣列上的以下 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` 上的以下方法：  
+ `prototype.isView`
+ `prototype.slice`

**Promise**  
支援 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` 模組。

**處理存取**  
沒有處理存取。例如沒有 `process` 全域物件可像 Node.js 一樣處理資訊存取。

**環境變數**  
無法存取環境變數。  
您可以改為使用 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 到 12 的一些功能。它還提供了一些不屬於 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`
`async`、`await`、`const` 和 `let` 是 JavaScript 執行時期 2.0 支援的功能。  
`await` 只能在 `async` 函數內使用，不支援 `async` 引數和關閉。

**文字**  
支援 ES 6 範本文字：多行字串、表達式插補和巢狀範本。

**函數**  
支援所有 ES 5.1 函數功能。  
支援 ES 6 箭頭函數，支援 ES 6 剩餘參數語法。

**Unicode**  
來源文字和字串常值可以包含 Unicode 編碼的字元。也支援由六個字元 (例如 `\uXXXX`) 組成的 Unicode 字碼指標逸出序列。

**嚴格模式**  
函數按預設會在嚴格模式下運作，因此您不需要在函數程式碼中新增 `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()`

**String**  
支援以下針對字串的 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 的新功能。

**Number**  
支援所有 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 的新功能。

**Symbol**  
支援以下 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()`

**主控台**  
這是一個用於偵錯的協助程式物件。它僅支援 `log()` 方法以記錄日誌訊息。  
CloudFront Functions 不支援逗號語法，例如 `console.log('a', 'b')`。因此請改為使用 `console.log('a' + ' ' + 'b')` 格式。

## 錯誤類型
<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**
+ [緩衝區](#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)

### 緩衝區
<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)`

  將 `Int8` `value` (長度為 `byteLength`) 寫入 `Buffer` 的偏移值 `offset`。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeIntBE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeInt16BE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeInt32BE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeIntLE(offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `offset`：輸入整數。
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeInt16LE(offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `offset`：輸入整數。
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeInt32LE(offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `offset`：輸入整數。
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeUInt8(value, offset, byteLength)`

  將 `UInt8` `value` (長度為 `byteLength`) 寫入 `Buffer` 的偏移值 `offset`。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeUIntBE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeUInt16BE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeUInt32BE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeUIntLE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeUInt16LE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeUInt32LE(value, offset, byteLength)`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `value`：輸入整數。
  + `offset`：輸入整數
  + `byteLength`：輸入從 `1` 到 `6` 的整數。
+ `Buffer.prototype.writeDoubleBE(value, [offset])`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：選用。輸入整數。預設值為 0。
+ `Buffer.prototype.writeDoubleLE(value, [offset])`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `value`：輸入整數。
  + `offset`：選用。輸入整數。預設值為 0。
+ `Buffer.prototype.writeFloatBE(value, [offset])`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用大端序。
  + `value`：輸入整數。
  + `offset`：選用。輸入整數。預設值為 0。
+ `Buffer.prototype.writeFloatLE(value, [offset])`

  將 `value` 寫入 `Buffer` 的偏移值 `offset`，使用小端序。
  + `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` 模組。

**處理存取**  
沒有處理存取。例如沒有 `process` 全域物件可像 Node.js 一樣處理資訊存取。

**環境變數**  
無法存取環境變數。您可以改為使用 CloudFront KeyValueStore 為您的 CloudFront Functions 建立鍵值對的集中式資料儲存。CloudFront KeyValueStore 可動態更新組態資料，不需要部署程式碼變更。如需詳細資訊，請參閱[Amazon CloudFront KeyValueStore](kvs-with-functions.md)。

**網路存取**  
不支援網路呼叫。例如，不支援 XHR、HTTP(S) 和通訊端。

# 鍵值存放區的協助程式方法
<a name="functions-custom-methods"></a>

**注意**  
CloudFront Functions 的鍵值存放區 helper 方法呼叫不會觸發 AWS CloudTrail 資料事件。這些事件不會記錄在 CloudTrail 事件歷史記錄中。如需詳細資訊，請參閱[使用 記錄 Amazon CloudFront API 呼叫 AWS CloudTrail](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"});
```

**回應**

回應是 `promise`，會以使用 `options` 請求的格式解析為值。根據預設，值會以字串傳回。

### 錯誤處理
<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}
```

# 原始伺服器修改的 Helper 方法
<a name="helper-functions-origin-modification"></a>

如果您動態更新或變更 CloudFront Functions 程式碼內請求所使用的原始伺服器，則本節適用。您只能在*檢視器請求* CloudFront Functions 時更新原始伺服器。CloudFront Functions 有一個模組，提供 helper 方法來動態更新或變更原始伺服器。

若要使用此模組，請使用 JavaScript 執行時期 2.0 建立 CloudFront 函數，並在函數程式碼的第一行中包含下列陳述式：

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

如需詳細資訊，請參閱[適用於 CloudFront Functions 的 JavaScript 執行時期 2.0 功能](functions-javascript-runtime-20.md)。

**注意**  
測試 API 和測試主控台頁面不會測試是否已發生原始伺服器修改。不過，測試可確保函數程式碼執行時不會發生錯誤。

## 在 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 更新原始伺服器，請參閱下列主題中的 helper 方法。

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 （選用，適用於non-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。使用 Origin Shield 有利於降低原始伺服器的負載。如需詳細資訊，請參閱[使用 Amazon CloudFront Origin Shield](origin-shield.md)。如果未提供，則會使用來自指派原始伺服器的 Origin Shield 設定。    
**enabled (必要)**  
啟用或停用 Origin Shield 的布林值表達式。接受值：`true` 或 `false`。  
**region (啟用時需要)**  
 AWS 區域 適用於 Origin Shield 的 。指定對原始伺服器延遲最低的 AWS 區域 。使用區域代碼，而非區域名稱。例如，使用 `us-east-2` 指定美國東部 (俄亥俄) 區域。  
啟用 CloudFront Origin Shield 時，您必須為其指定 AWS 區域 。如需可用 AWS 區域 的清單並協助您選擇最適合原始伺服器的區域，請參閱 [選擇 Origin Shield AWS 的區域](origin-shield.md#choose-origin-shield-region)。

**originAccessControlConfig (選用)**  
此原始伺服器的原始存取控制 (OAC) 唯一識別碼。這只會在原始伺服器支援 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`。

**timeout (選用)**  
您可以指定 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 （選用，適用於non-S3 自訂原始伺服器）**  
伺服器名稱指示 (SNI) 是 Transport Layer Security (TLS) 通訊協定的延伸，其中用戶端會指出其嘗試在 TLS 交握程序開始時連線到哪個主機名稱。此值應與原始伺服器上 TLS 憑證上的通用名稱相符。否則，您的原始伺服器可能會擲回錯誤。  
如果未提供，則會使用 `hostHeader` 參數中的 值。如果未提供主機標頭，則會使用 `domainName` 參數的值。  
如果未提供主機標頭或網域名稱參數，則會使用指派原始伺服器的網域名稱，如果轉送至原始伺服器 (FTO) 政策包含主機，則會使用來自傳入請求的主機標頭。SNI 不能包含冒號 (`:`)，也不能是 IP 地址。SNI 最多可達 253 個字元。

**allowedCertificateNames （選用，適用於non-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 – 更新 Application Load Balancer 請求原始伺服器**  
下列範例會將檢視器請求的原始伺服器變更為 Application Load Balancer 原始伺服器，並設定自訂標頭和逾時。  

```
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 – 在啟用 Origin Shield 的情況下更新原始伺服器**  
在下列範例中，分佈中的原始伺服器已啟用 Origin Shield。函數程式碼只會更新用於原始伺服器的網域名稱，並省略所有其他選用參數。在此情況下，Origin Shield 仍會與修改後的原始網域名稱搭配使用，因為 Origin Shield 參數未更新。  

```
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 參考，這是您在設定原始伺服器時定義的原始伺服器名稱。

如果您的分佈中已設定 VPC 原始伺服器，您可以使用此方法將原始伺服器更新為 VPC 原始伺服器。如需詳細資訊，請參閱[使用 VPC 原始伺服器限制存取](private-content-vpc-origins.md)。

**備註**  
`selectRequestOriginById()` 函數無法選取已啟用交互 TLS （原始伺服器） 的原始伺服器。嘗試使用此函數選取已啟用交互 TLS （原始伺服器） 的原始伺服器會導致驗證錯誤。
如果您的使用案例需要使用交互 TLS （原始伺服器） 來選擇動態原始伺服器，請`updateRequestOrigin()`改用 ，確保所有目標原始伺服器都使用相同的用戶端憑證。

**請求**

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

在先前的範例中， `origin_id` 是一個字串，指向執行 函數之 分佈中原始伺服器的原始伺服器名稱。`origin_overrides `參數可以包含下列項目：

**hostHeader （選用，適用於non-S3 自訂原始伺服器）**  
向原始伺服器提出請求時要使用的主機標頭。如果未提供，則會使用 `domainName` 參數中的 值。  
如果未提供主機標頭或網域名稱參數，則會使用指派原始伺服器的網域名稱，如果轉送至原始伺服器 (FTO) 政策包含主機，則會使用來自傳入請求的主機標頭。主機標頭不能包含冒號 (`:`)，也不能是 IP 地址。主機標頭最多可達 253 個字元。

**sni （選用，適用於non-S3 自訂原始伺服器）**  
伺服器名稱指示 (SNI) 是 Transport Layer Security (TLS) 通訊協定的延伸，其中用戶端會指出其嘗試在 TLS 交握程序開始時連線到哪個主機名稱。此值應與原始伺服器上 TLS 憑證上的通用名稱相符。否則，您的原始伺服器可能會擲回錯誤。  
如果未提供，則會使用 `hostHeader` 參數中的 值。如果未提供主機標頭，則會使用 `domainName` 參數的值。  
如果未提供主機標頭或網域名稱參數，則會使用指派原始伺服器的網域名稱，如果轉送至原始伺服器 (FTO) 政策包含主機，則會使用來自傳入請求的主機標頭。SNI 不能包含冒號 (`:`)，也不能是 IP 地址。SNI 最多可達 253 個字元。

**allowedCertificateNames （選用，適用於non-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 – 選取 Application Load Balancer 請求原始伺服器**  
下列範例會從與分佈相關聯的原始伺服器清單中選擇名為 `myALB-prod` 的 Application Load Balancer 原始伺服器，並將 `myALB-prod` 的組態設定套用至請求。  

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

**Example – 選取 Application Load Balancer 請求原始伺服器並覆寫主機標頭**  
如同上述範例，下列範例`myALB-prod`會從與分佈相關聯的原始伺服器清單中選擇名為 的 Application Load Balancer 原始伺服器，並將 的組態設定套用至`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 （選用，適用於non-S3 自訂原始伺服器）**  
向原始伺服器提出請求時要使用的主機標頭。如果未提供，則會使用 `domainName` 參數中的 值。  
如果未提供主機標頭或網域名稱參數，則會使用指派原始伺服器的網域名稱，如果轉送至原始伺服器 (FTO) 政策包含主機，則會使用來自傳入請求的主機標頭。主機標頭不能包含冒號 (`:`)，也不能是 IP 地址。主機標頭最多可達 253 個字元。  
**sni （選用，適用於non-S3 自訂原始伺服器）**  
伺服器名稱指示 (SNI) 是 Transport Layer Security (TLS) 通訊協定的延伸，用戶端會在 TLS 交握程序開始時，指出其嘗試連線到哪個主機名稱。此值應與原始伺服器上 TLS 憑證上的通用名稱相符，否則原始伺服器可能會擲回錯誤。  
如果未提供，則會使用 `hostHeader` 參數中的 值。如果未提供主機標頭，則會使用 `domainName` 參數的值。  
如果未提供主機標頭或網域名稱參數，則會使用指派原始伺服器的網域名稱，如果轉送至原始伺服器 (FTO) 政策包含主機，則會使用來自傳入請求的主機標頭。SNI 不能包含冒號 (`:`)，也不能是 IP 地址。SNI 最多可達 253 個字元。  
**allowedCertificateNames （選用，適用於non-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 屬性的 helper 方法
<a name="saas-specific-logic-function-code"></a>

使用 CloudFront SaaS Manager 的下列 helper 函數，在您建立的函數中擷取多租用戶分佈的值。若要在此頁面上使用範例，您必須先使用 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` 欄位才會出現。如需詳細資訊，請參閱[內容物件](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 提供處理 `Promise` 物件的 `async` 和 `await` 語法。Promises 代表可以透過函數中標記為 `async` 的關鍵字 `await` 存取延遲結果。各種新的 WebCrypto 函數使用 Promises。

如需 `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` 鏈接方法查看 Promises。您可以使用 `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 Token (CWT) 支援的詳細資訊，可在 CloudFront Edge Locations 啟用安全字符型身分驗證和授權。此支援是以模組形式提供，可在 CloudFront Function 中存取。

若要使用此模組，請使用 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 結構，字符大小上限為 1KB。

## 字符結構
<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})
```Parameters

**字符 （必要）**  
用於驗證的編碼字符。這必須是 JavaScript 緩衝區。

**handlerContext （必要）**  
存放 validateToken 呼叫內容的 JavaScript 物件。目前僅支援 金鑰屬性。

**金鑰 （必要）**  
訊息摘要運算的私密金鑰。可做為字串或 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)
```Parameters

**generatorContext （必要）**  
這是 JavaScript 物件，可做為產生字符的內容，並包含下列索引鍵值對：    
**cwtTag （選用）**  
此值是布林值，如果 `true`指定`cwtTag`應新增 。  
**coseTag （必要）**  
指定 COSE 標籤類型。目前僅支援 `MAC0`。  
**金鑰 （必要）**  
用於運算訊息摘要的私密金鑰。此值可以是字串或 JavaScript `Buffer`。

**承載 （必要）**  
用於編碼的字符承載。承載必須是 `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 Regional Edge Cache (REC)。如果預期的 REC 無法使用，且請求使用備份 REC，則不會更新此值。這不包括正在使用的 Origin Shield 位置，除非主要 REC 和 Origin Shield 是相同的位置。

**注意**  
當 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`

# 建立函數
<a name="create-function"></a>

您可以分兩個階段建立函數：

1. 建立函數程式碼做為 JavaScript。您可以從 CloudFront 主控台使用預設範例或自行撰寫。如需詳細資訊，請參閱下列主題：
   + [撰寫函數程式碼](writing-function-code.md)
   + [CloudFront Functions 事件結構](functions-event-structure.md)
   + [CloudFront 的 CloudFront Functions 範例](service_code_examples_cloudfront_functions_examples.md)

1. 然後，您可以使用 CloudFront 建立函數並包含程式碼。程式碼存在於函數內部 (而不是引用形式)。

------
#### [ Console ]

**建立 函數**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions) 登入 CloudFront 主控台，並選擇**函數**頁面。

1. 選擇 **Create function (建立函數)**。

1. 輸入在 AWS 帳戶 內唯一的函數名稱，然後選擇 JavaScript 版本，接著選擇**繼續**。新函數的詳細資訊頁面會隨即顯示。
**注意**  
如要在函數中使用[鍵值對](kvs-with-functions.md)，您必須選擇 JavaScript 執行時期 2.0。

1. 在**函數程式碼**區段中，選擇**建置**索引標籤，然後輸入您的函數程式碼。**建置**索引標籤中包含的範例程式碼會說明函數程式碼的基本語法。

1. 選擇**儲存變更**。

1. 如果函數程式碼使用鍵值對，則必須關聯鍵值存放區。

   在首次建立函數時，您可以關聯鍵值存放區。或者，您可以稍後透過[更新函數](update-function.md)來關聯它。

   若要立即關聯鍵值存放區，請依照下列步驟執行：
   + 前往**關聯 KeyValueStore** 區段，然後選擇**關聯現有的 KeyValueStore**。
   + 選取函數中包含鍵值對的鍵值存放區，然後選擇**關聯 KeyValueStore**。

   CloudFront 會立即將存放區與該函數建立關聯。您無需儲存函數。

------
#### [ CLI ]

如果您使用 CLI，通常會先在檔案中建立函數程式碼，然後使用 AWS CLI 來建立函數。

**建立 函數**

1. 在檔案中建立函數程式碼，並將其儲存於電腦可以連線的目錄中。

1. 執行命令，如範例所示。此範例會使用 `fileb://` 標記法來傳入檔案。它還會包括換行符號，讓命令更易於讀取。

   ```
   aws cloudfront create-function \
       --name MaxAge \
       --function-config '{"Comment":"Max Age 2 years","Runtime":"cloudfront-js-2.0","KeyValueStoreAssociations":{"Quantity":1,"Items":[{"KeyValueStoreARN":"arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"}]}}' \
       --function-code fileb://function-max-age-v1.js
   ```
**備註**  
`Runtime` – JavaScript 版本。如要在函數中使用[鍵值對](kvs-with-functions.md)，您必須指定版本 2.0。
`KeyValueStoreAssociations` – 如果您的函數使用鍵值對，則可以在初次建立函數時關連鍵值存放區。或者，您可以稍後使用 `update-function` 來關聯它。`Quantity` 永遠等於 `1`，因為每個函數只能有一個與其關聯的鍵值存放區。

   如果命令成功執行，您會看到如下所示的輸出。

   ```
   ETag: ETVABCEXAMPLE
   FunctionSummary:
     FunctionConfig:
       Comment: Max Age 2 years
       Runtime: cloudfront-js-2.0
       KeyValueStoreAssociations= \
         {Quantity=1, \
         Items=[{KeyValueStoreARN='arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111'}]} \
     FunctionMetadata:
       CreatedTime: '2021-04-18T20:38:56.915000+00:00'
       FunctionARN: arn:aws:cloudfront::111122223333:function/MaxAge
       LastModifiedTime: '2023-11-19T20:38:56.915000+00:00'
       Stage: DEVELOPMENT
     Name: MaxAge
     Status: UNPUBLISHED
   Location: https://cloudfront.amazonaws.com/2020-05-31/function/arn:aws:cloudfront:::function/MaxAge
   ```

   大多數資訊都是從請求中複製的。其他資訊會由 CloudFront 新增。
**備註**  
`ETag` – 每次修改鍵值存放區時，這個值都會變更。您可以使用此值和函數名稱，以在未來參考函數。確保始終使用目前的 `ETag`。
`FunctionARN` – CloudFront 函數的 ARN。
111122223333 – AWS 帳戶。
`Stage` – 函數的階段 (`LIVE` 或 `DEVELOPMENT`)。
`Status` – 函數的狀態 (`PUBLISHED` 或 `UNPUBLISHED`)。

------

建立函數之後，該函數會新增至 `DEVELOPMENT` 階段。建議您[在發佈函數](publish-function.md)之前進行[測試](test-function.md)。發佈函數之後，函數會變更為 `LIVE` 階段。

# 測試函數
<a name="test-function"></a>

在將函數部署到即時階段 (生產環境) 之前，可以測試該函數以確保其運作正常。若要測試函數，您可以指定一個*事件物件*，代表您的 CloudFront 分佈可在生產環境中接收的 HTTP 請求或回應。

CloudFront Functions 會執行下列作業：

1. 執行該函數，使用提供的事件物件作為函數的輸入。

1. 返回函數的結果 (修改後的事件物件)，同時返回任何函數日誌或錯誤訊息以及函數的*運算利用率*。如需運算使用率的詳細資訊，請參閱 [了解運算利用率](#compute-utilization)。

**注意**  
當您測試函數時，CloudFront 只會驗證函數執行錯誤。CloudFront 不會驗證發佈後請求是否成功通過。例如，如果您的函數刪除必要的標頭，測試將會成功，因為程式碼沒有問題。不過，如果您發佈函數並將其與分佈建立關聯，則函數會在透過 CloudFront 提出請求時失敗。

**Contents**
+ [設定事件物件](#test-function-create-event)
+ [測試函數](#test-function-step-test)
+ [了解運算利用率](#compute-utilization)

## 設定事件物件
<a name="test-function-create-event"></a>

在測試函數之前，您必須建立事件物件以進行測試。有幾種選項。

**選項 1：設定事件物件而不儲存**  
您可以在 CloudFront 主控台的視覺化編輯器中設定事件物件，而不儲存該事件物件。  
您可以使用此事件物件從 CloudFront 主控台測試函數，即使該函數尚未儲存也是如此。

**選項 2：在視覺化編輯器中建立事件物件**  
您可以在 CloudFront 主控台的視覺化編輯器中設定事件物件，而不儲存該事件物件。您可以針對每個函數建立 10 個事件物件，例如，可測試不同的可能輸入。  
以這種方式建立事件物件時，您可以使用事件物件，在 CloudFront 主控台中測試函數。您無法使用它來測試使用 AWS API 或 SDK 的函數。

**選項 3：使用文字編輯器建立事件物件**  
您可以使用文字編輯器，以 JSON 格式建立事件物件。如需有關事件物件結構的詳細資訊，請參閱 [事件結構](functions-event-structure.md)。  
您可以使用此事件物件來測試使用 CLI 的函數。但是您無法使用它來測試 CloudFront 主控台中的函數。

**建立事件物件 (選項 1 或 2)**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions) 登入 CloudFront 主控台，並選擇**函數**頁面。

   選擇您要測試的函數。

1. 在函數詳細資訊頁面上，選擇**測試**索引標籤。

1. 針對**事件類型**，選擇以下其中一個選項：
   + 如果函數會根據請求修改 HTTP 請求或產生回應，請選擇**檢視者請求**。**請求**區段隨即出現。
   + 選擇**檢視器回應**。**請求**和**回應**區段隨即出現。

1. 完成您想要包含在事件中的所有欄位。您可選擇**編輯 JSON** 來檢視原始 JSON。

1. (選用) 若要儲存事件，請選擇**儲存**，然後在**儲存測試事件**中輸入名稱，然後選擇**儲存**。

   您也可以選擇**編輯 JSON** 並複製原始 JSON，並將其儲存在 CloudFront 之外您自己的檔案中。

**建立事件物件 (選項 3)**

使用文字編輯器建立事件物件。將檔案儲存於電腦可以連線的目錄中。

請確定您遵循這些準則：
+ 省略 `distributionDomainName`、`distributionId` 和 `requestId` 欄位。
+ 標頭、Cookie 和查詢字串的名稱必須為小寫。

以這種方式建立事件物件的一個選項是使用視覺化編輯器建立範例。您可以確定範例格式正確。然後您可以複製原始 JSON 並將其貼到文字編輯器中並儲存檔案。

如需有關事件結構的詳細資訊，請參閱 [事件結構](functions-event-structure.md)。

## 測試函數
<a name="test-function-step-test"></a>

您可以在 CloudFront 主控台或使用 AWS Command Line Interface () 測試函數AWS CLI。

------
#### [ Console ]

**若要測試函數**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions) 登入 CloudFront 主控台，並選擇**函數**頁面。

1. 選擇您要測試的函數。

1. 選擇**測試**標籤。

1. 確定已顯示正確的事件。若要從目前顯示的事件切換，請在**選取測試事件**欄位中選擇另一個事件。

1. 選擇**測試函數**。控制台顯示函數的輸出，包括函數日誌和運算使用率。

------
#### [ CLI ]

您可以使用 **aws cloudfront test-function** 命令來測試函數。

**若要測試函數**

1. 開啟命令列視窗。

1. 從包含指定檔案的目錄執行下列命令。

   此範例會使用 `fileb://` 標記法來傳入事件物件檔案。它還會包括換行符號，讓命令更易於讀取。

   ```
   aws cloudfront test-function \
       --name MaxAge \
       --if-match ETVABCEXAMPLE \
       --event-object fileb://event-maxage-test01.json \
       --stage DEVELOPMENT
   ```
**備註**  
您可以透過其名稱和 ETag (在 `if-match` 參數中) 引用該函數。您可以依照事件物件在檔案系統中的位置來參照事件物件。
此階段可以是 `DEVELOPMENT` 或 `LIVE`。

   如果命令成功執行，您會看到如下所示的輸出。

   ```
   TestResult:
     ComputeUtilization: '21'
     FunctionErrorMessage: ''
     FunctionExecutionLogs: []
     FunctionOutput: '{"response":{"headers":{"cloudfront-functions":{"value":"generated-by-CloudFront-Functions"},"location":{"value":"https://aws.amazon.com/cloudfront/"}},"statusDescription":"Found","cookies":{},"statusCode":302}}'
     FunctionSummary:
       FunctionConfig:
         Comment: MaxAge function
         Runtime: cloudfront-js-2.0
         KeyValueStoreAssociations= \
         {Quantity=1, \
         Items=[{KeyValueStoreARN='arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111'}]} \
       FunctionMetadata:
         CreatedTime: '2021-04-18T20:38:56.915000+00:00'
         FunctionARN: arn:aws:cloudfront::111122223333:function/MaxAge
         LastModifiedTime: '2023-17-20T10:38:57.057000+00:00'
         Stage: DEVELOPMENT
       Name: MaxAge
       Status: UNPUBLISHED
   ```

------

**備註**  
`FunctionExecutionLogs` 包含函數在 `console.log()` 語句中撰寫的日誌行清單 (如果有的話)。
`ComputeUtilization` 包含執行函數的相關資訊。請參閱 [了解運算利用率](#compute-utilization)。
`FunctionOutput` 包含該函數返回的事件物件。

## 了解運算利用率
<a name="compute-utilization"></a>

**運用利用率**是指執行函數所花費的時間，以所允許時間上限的百分比表示。例如，值為 35 表示函數在最大允許時間的 35% 內完成。

如果某個函數持續時間，超過允許時間上限，則 CloudFront 會將該函數限流。下列清單說明，根據運算利用率的值，函數限流的可能性。

**運算利用率值：**
+ **1 — 50**— 函數遠低於允許時間上限，應不會受到限流。
+ **51 — 70**— 函數接近允許時間上限。考慮將函數程式碼最佳化。
+ **71 — 100**— 函數非常接近或超過允許時間上限。如果您將此函數與分佈產生關聯，CloudFront 很有可能會將此函數限流。

# 更新函數
<a name="update-function"></a>

您隨時都可以更新。這些變更只會對 `DEVELOPMENT` 階段中的函數版本進行。若要將更新從 `DEVELOPMENT` 階段複製到 `LIVE`，您必須[發佈函數](publish-function.md)。

您可以在 CloudFront 主控台中或使用 AWS Command Line Interface (AWS CLI) 更新函數的程式碼。

------
#### [ Console ]

**更新函數程式碼**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions) 登入 CloudFront 主控台，並選擇**函數**頁面。

   選擇要更新的函數。

1. 選擇**編輯**，然後進行您想要的變更：
   + 更新**詳細資訊**區段中的任何欄位。
   + 變更或移除關聯的鍵值存放區。如需鍵值存放區的詳細資訊，請參閱 [Amazon CloudFront KeyValueStore](kvs-with-functions.md)。
   + 變更函數程式碼。選擇**建置**索引標籤，進行變更，然後選擇**儲存變更**，儲存對程式碼的變更。

------
#### [ CLI ]

**若要更新函數程式碼**

1. 開啟命令列視窗。

1. 執行下列命令。

   此範例會使用 `fileb://` 標記法來傳入檔案。它還會包括換行符號，讓命令更易於讀取。

   ```
   aws cloudfront update-function \
       --name MaxAge \
       --function-config '{"Comment":"Max Age 2 years","Runtime":"cloudfront-js-2.0","KeyValueStoreAssociations":{"Quantity":1,"Items":[{"KeyValueStoreARN":"arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"}]}}' \
       --function-code fileb://function-max-age-v1.js \
       --if-match ETVABCEXAMPLE
   ```
**備註**  
您可以透過名稱和 ETag (在 `if-match` 參數中) 來識別函數。請確定您使用目前的 ETag。您可以從 [DescribeFunction](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DescribeFunction.html) API 作業取得此值。
即使您不想要變更，您也必須包含 `function-code`。
要小心 `function-config`。您應該傳遞您想要在組態中保留的所有內容。具體而言，請依下列方式處理鍵值存放區：  
若要保留現有的鍵值存放區關聯 (如果有的話)，請指定*現有*存放區的名稱。
若要變更關聯，請指定*新*鍵值存放區的名稱。
若要移除關聯，請省略 `KeyValueStoreAssociations` 參數。

   如果命令成功執行，您會看到如下所示的輸出。

   ```
   ETag: ETVXYZEXAMPLE
   FunctionSummary:
     FunctionConfig:
       Comment: Max Age 2 years \
       Runtime: cloudfront-js-2.0 \
       KeyValueStoreAssociations= \
         {Quantity=1, \
         Items=[{KeyValueStoreARN='arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111'}]} \
     FunctionMetadata: \
       CreatedTime: '2021-04-18T20:38:56.915000+00:00' \
       FunctionARN: arn:aws:cloudfront::111122223333:function/MaxAge \
       LastModifiedTime: '2023-12-19T23:41:15.389000+00:00' \
       Stage: DEVELOPMENT \
     Name: MaxAge \
     Status: UNPUBLISHED
   ```

------

大多數資訊都是從請求中複製的。其他資訊會由 CloudFront 新增。

**備註**  
`ETag` – 每次修改鍵值存放區時，這個值都會變更。
`FunctionARN` – CloudFront 函數的 ARN。
`Stage` – 函數的階段 (`LIVE` 或 `DEVELOPMENT`)。
`Status` – 函數的狀態 (`PUBLISHED` 或 `UNPUBLISHED`)。

# 發佈函數
<a name="publish-function"></a>

您發佈函數時，這會將函數從 `DEVELOPMENT` 階段複製到 `LIVE` 階段。

如果沒有與函數相關聯的快取行為，發佈該函數可讓您將其與快取行為產生關聯。您只能將快取行為與 `LIVE` 階段中的函數產生關聯。

**重要**  
建議您在發佈之前先[測試函數](test-function.md)。
發佈函數後，與該函數相關聯的所有快取行為會在分佈完成部署後立即開始使用新發佈的副本。

您可以在 CloudFront 主控台中或使用 AWS CLI 發佈函數。

------
#### [ Console ]

**發佈函數**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions) 登入 CloudFront 主控台，並選擇**函數**頁面。

1. 選擇要更新的函數。

1. 選擇**發佈**索引標籤，然後選擇**發佈**。如果您的函數已附加至一或多個快取行為，請選擇**發佈並更新**。

1. (選用) 若要檢視與函數相關聯的分佈，請選擇**關聯的 CloudFront 分佈**以展開該區段。

成功後，您會在頁面頂端看到一個橫幅，顯示**已成功發佈*函數名稱***。您也可以選擇**建置**索引標籤，然後選擇**即時**以檢視函數程式碼的即時版本。

------
#### [ CLI ]

**發佈函數**

1. 開啟命令列視窗。

1. 執行下列 **aws cloudfront publish-function** 命令。在此範例中，提供分行符號以使範例更具可讀性。

   ```
   aws cloudfront publish-function \
       --name MaxAge \
       --if-match ETVXYZEXAMPLE
   ```

   如果命令成功執行，您會看到如下所示的輸出。

   ```
   FunctionSummary:
     FunctionConfig:
       Comment: Max Age 2 years
       Runtime: cloudfront-js-2.0
     FunctionMetadata:
       CreatedTime: '2021-04-18T21:24:21.314000+00:00'
       FunctionARN: arn:aws:cloudfront::111122223333:function/ExampleFunction
       LastModifiedTime: '2023-12-19T23:41:15.389000+00:00'
       Stage: LIVE
     Name: MaxAge
     Status: UNASSOCIATED
   ```

------

# 將函數與分佈相關聯
<a name="associate-function"></a>

若要將函數與分佈搭配使用，請將該函數與分佈中的一或多個快取行為建立關聯。您可以將函數與多個分佈中的多個快取行為相關聯。

您可以將函數與下列任何行為建立關聯：
+ 現有的快取行為
+ 現有分佈中新的新快取行為
+ 新分佈中的新快取行為

將函數與快取行為建立關聯時，您必須選擇*事件類型*。事件類型決定 CloudFront 何時執行該函數。

您可以選擇下列事件類型：
+ **檢視者請求** – 當 CloudFront 收到來自檢視者的請求時，該函數會執行。
+ **檢視者回應** – 此函數會在 CloudFront 傳回檢視者回應之前執行。

您不能將面向原始伺服器的事件類型 (*原始伺服器請求*和*原始伺服器回應*) 與 CloudFront Functions 搭配使用。您可以改為使用 Lambda@Edge。如需更多詳細資訊，請參閱 [可以觸發 Lambda@Edge 函數的 CloudFront 事件](lambda-cloudfront-trigger-events.md)。

**注意**  
在關聯函數之前，您必須將[其發佈](publish-function.md)至 `LIVE` 階段。

您可以將函數與 CloudFront 主控台中的分佈建立關聯，或與 AWS Command Line Interface (AWS CLI) 建立關聯。下列程序顯示如何將函數與現有的快取行為建立關聯。

------
#### [ Console ]

**將函數與現有快取行為產生關聯**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions) 登入 CloudFront 主控台，並選擇**函數**頁面。

1. 選擇您要關聯的函數。

1. 在**函數**頁面上，選擇**發佈**索引標籤。

1. 選擇**發佈函數**。

1. 選擇 **Add association (建立關聯)**。在出現的對話方塊中，選擇分佈、事件類型及/或快取行為。

   在事件類型中，選擇您希望此函數執行的時間：
   + **檢視器請求** – 在 CloudFront 每次收到請求時執行該函數。
   + **檢視器回應** – 在 CloudFront 每次傳回回應時執行該函數。

1. 若要儲存組態，請選擇**新增關聯**。

CloudFront 會將分佈與函數建立關聯。等待幾分鐘，讓關聯的分佈完成部署。您可以在函數詳細資訊頁面上選擇**檢視分佈**來檢查進度。

------
#### [ CLI ]

**將函數與現有快取行為產生關聯**

1. 開啟命令列視窗。

1. 使用下列命令儲存分佈的組態，該分佈的快取行為將與函數產生關聯。此命令會將分佈組態儲存到名為 `dist-config.yaml` 的檔案中。若要使用此命令，請執行下列動作：
   + 將 *`DistributionID`* 取代為分佈的 ID。
   + 在一行上執行命令。在此範例中，提供分行符號以使範例更具可讀性。

   ```
   aws cloudfront get-distribution-config \
       --id DistributionID \
       --output yaml > dist-config.yaml
   ```

   命令成功時，AWS CLI 不會返回任何輸出。

1. 開啟您建立且命名為 `dist-config.yaml` 的檔案。編輯檔案以進行下列變更。

   1. 將 `ETag` 欄位重新命名為 `IfMatch`，但不要變更欄位的值。

   1. 在快取行為中，尋找名為 `FunctionAssociations` 的物件。更新此物件以新增函數關聯。如下的範例給出函數關聯的 YAML 語法。
      + 下列範例顯示檢視者請求事件物件 (觸發條件)。若要使用檢視者回應事件類型，請將 `viewer-request` 取代為 `viewer-response`。
      + 將 *`arn:aws:cloudfront::111122223333:function/ExampleFunction`* 取代為與此快取行為相關聯之函數的 Amazon Resource Name (ARN)。要獲取函數 ARN，您可以使用 **aws cloudfront list-functions** 命令。

      ```
      FunctionAssociations:
        Items:
          - EventType: viewer-request
            FunctionARN: arn:aws:cloudfront::111122223333:function/ExampleFunction
        Quantity: 1
      ```

   1. 進行這些變更後，請儲存檔案。

1. 使用以下命令更新分佈，同時新增函數關聯。若要使用此命令，請執行下列動作：
   + 將 *`DistributionID`* 取代為分佈的 ID。
   + 在一行上執行命令。在此範例中，提供分行符號以使範例更具可讀性。

   ```
   aws cloudfront update-distribution \
       --id DistributionID \
       --cli-input-yaml file://dist-config.yaml
   ```

   如果命令成功執行，您會看到如下所示的輸出，其中描述剛使用函數關聯更新的分佈。為便於閱讀，對如下的範例輸出進行了截斷。

   ```
   Distribution:
     ARN: arn:aws:cloudfront::111122223333:distribution/EBEDLT3BGRBBW
     ... truncated ...
     DistributionConfig:
       ... truncated ...
       DefaultCacheBehavior:
         ... truncated ...
         FunctionAssociations:
           Items:
           - EventType: viewer-request
             FunctionARN: arn:aws:cloudfront::111122223333:function/ExampleFunction
           Quantity: 1
         ... truncated ...
     DomainName: d111111abcdef8.cloudfront.net
     Id: EDFDVBD6EXAMPLE
     LastModifiedTime: '2021-04-19T22:39:09.158000+00:00'
     Status: InProgress
   ETag: E2VJGGQEG1JT8S
   ```

------

重新部署分佈時，此分佈的 `Status` 變更為 `InProgress`。一旦新的分佈組態到達 CloudFront 邊緣節點，該邊緣節點就會開始使用關聯的函數。當分佈完全部署時，`Status` 會變更回 `Deployed`。這表示相關聯的 CloudFront 函數已在全球所有 CloudFront 邊緣節點中上線。通常這需要幾分鐘的時間。

# Amazon CloudFront KeyValueStore
<a name="kvs-with-functions"></a>

CloudFront KeyValueStore 是安全、全域、低延遲的鍵值資料儲存，可從 [CloudFront Functions](cloudfront-functions.md) 內進行讀取存取，從而在 CloudFront 邊緣節點啟用進階可自訂邏輯。

使用 CloudFront KeyValueStore，您可以更新函數程式碼，並且彼此獨立地更新與函數相關聯的資料。這種分離簡化了函數程式碼，並且可以輕鬆更新資料，而無需部署程式碼變更。

**注意**  
若要使用 CloudFront KeyValueStore，您的 CloudFront 函數必須使用 [JavaScript 執行時期 2.0](functions-javascript-runtime-20.md)。

使用鍵值對的一般程序如下：
+ 建立鍵值存放區，並填入一組鍵值對。您可以將鍵值存放區新增至 Amazon S3 儲存貯體，或手動輸入。
+ 將鍵值存放區與您的 CloudFront 函數建立關聯。
+ 在函數程式碼中，使用鍵的名稱來擷取與鍵關聯的值或評估鍵是否存在。如需有關在函數程式碼中使用鍵值對的詳細資訊，以及協助程式方法的相關資訊，請參閱 [鍵值存放區的協助程式方法](functions-custom-methods.md)。

## 使用案例
<a name="key-value-store-use-cases"></a>

您可以針對下列範例使用鍵值對：
+ **URL 重寫或重新導向**：鍵值對可以保留重寫 URL 或重新導向 URL。
+ **A/B 測試及功能旗標**：您可指派一定百分比的流量至特定版本網站，即可建立執行實驗的函數。
+ **存取授權**：您可實作存取控制，根據您定義的條件和鍵值存放區中儲存的資料來允許或拒絕請求。

## 支援的值格式
<a name="key-value-store-supported-formats"></a>

您可採用下列任何一種格式儲存鍵值對中的值：
+ String
+ 位元組編碼字串
+ JSON 

## 安全
<a name="key-value-store-security"></a>

CloudFront 函數及其所有鍵值存放區資料均可安全地處理，如下所示：
+ 您呼叫 [CloudFront KeyValueStore](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_Operations_Amazon_CloudFront_KeyValueStore.html) API 操作時，CloudFront 會在靜態和傳輸期間 (讀取或寫入鍵值存放區時) 將每個鍵值存放區加密。
+ 執行函數時，CloudFront 會解密 CloudFront 邊緣節點記憶體中的每個鍵值對。

若要開始使用 CloudFront KeyValueStore，請參閱下列主題。

**Topics**
+ [使用案例](#key-value-store-use-cases)
+ [支援的值格式](#key-value-store-supported-formats)
+ [安全](#key-value-store-security)
+ [使用鍵值存放區](kvs-with-functions-kvs.md)
+ [使用鍵值資料](kvs-with-functions-kvp.md)
+ 如需 CloudFront KeyValueStore 入門的詳細資訊，請參閱[簡介 Amazon CloudFront KeyValueStore](https://aws.amazon.com/blogs/aws/introducing-amazon-cloudfront-keyvaluestore-a-low-latency-datastore-for-cloudfront-functions/) AWS 部落格文章。

# 使用鍵值存放區
<a name="kvs-with-functions-kvs"></a>

您必須建立鍵值存放區，以保留要在 CloudFront Functions 中使用的鍵值對。

建立鍵值存放區並新增鍵值對之後，您可以在 CloudFront 函數程式碼中使用這些鍵值。

若要開始使用，請參閱下列主題：

**Topics**
+ [建立鍵值存放區](kvs-with-functions-create.md)
+ [將鍵值存放區與函數建立關聯。](kvs-with-functions-associate.md)
+ [更新鍵值存放區](kvs-with-functions-edit.md)
+ [獲取鍵值存放區參考資料](kvs-with-functions-get-reference.md)
+ [刪除鍵值存放區](kvs-with-functions-delete.md)
+ [鍵值對的檔案格式](kvs-with-functions-create-s3-kvp.md)

**注意**  
JavaScript 執行時期 2.0 包含一些協助程式方法，可用來處理函數程式碼中的鍵值。如需詳細資訊，請參閱[鍵值存放區的協助程式方法](functions-custom-methods.md)。

# 建立鍵值存放區
<a name="kvs-with-functions-create"></a>



您可以同時建立一個鍵值存放區及其鍵值對。您也可以建立一個空的鍵值存放區，並於稍後在其中新增鍵值對。

**注意**  
如果您從 Amazon S3 儲存貯體指定資料來源，就必須擁有該儲存貯體的 `s3:GetObject` 和 `s3:GetBucketLocation` 許可權限。如果您沒有這些許可權限，CloudFront 就無法成功建立您的鍵值存放區。

請決定是否要在建立鍵值存放區的同時新增鍵值對。您可以使用 CloudFront 主控台、CloudFront API 或 AWS SDKs匯入金鑰/值對。不過您只能在*最初*建立鍵值存放區時匯入鍵值對檔案。

若要建立鍵值對檔案，請參閱 [鍵值對的檔案格式](kvs-with-functions-create-s3-kvp.md)。

------
#### [ Console ]

**建立鍵值存放區**

1. 登入 ， AWS 管理主控台 並在位於 的 CloudFront 主控台中開啟**函數**頁面[https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)。

1. 選擇 **KeyValueStores** 索引標籤，然後選擇**建立 KeyValueStore**。

1. 輸入鍵值存放區的名稱，以及選擇性的描述。

1. 完成 **S3 URI**：
   + 如果您有鍵值對檔案，請輸入您存放該檔案的 Amazon S3 儲存貯體路徑。
   + 如果您打算手動輸入鍵值對，請將此欄位保留空白。

1. 選擇**建立**。鍵值存放區現已建立。

   此時會顯示新鍵值存放區的詳細資訊頁面。頁面上的資訊包括鍵值存放區的 ID 和 ARN。
   + ID 是在您 中唯一的隨機字元字串 AWS 帳戶。
   + ARN 具有以下語法：

     *AWS 帳戶*`:key-value-store/`* 鍵值存放區 ID*

1. 請查看**鍵值對**區段。如果您匯入檔案，此區段會顯示一些鍵值對。您可以執行下列動作：
   + 如果您匯入了檔案，也可以手動新增更多值。
   + 如果您沒有從 Amazon S3 儲存貯體匯入檔案，而且現在想要新增鍵值對，則可以完成下個步驟。
   + 您可以略過此步驟，稍後再新增鍵值對。

1. 立即新增鍵值對：

   1. 選擇**新增鍵值對**。

   1. 選擇**新增配對**，然後輸入名稱和值。若要新增更多配對，請重複此步驟。

   1. 完成後，選擇**儲存變更**以儲存鍵值存放區中的所有鍵值對。在出現的對話方塊中選擇**完成**。

1. 如果您要立即將鍵值存放區與函數相關聯，請完成**關聯函數**區段。如需詳細資訊，請參閱 [建立函數](create-function.md) 或 [更新函數](update-function.md) 。

   您也可以稍後從此鍵值存放區詳細資訊頁面或從函數詳細資訊頁面與函數建立關聯。

------
#### [ AWS CLI ]

**建立鍵值存放區**
+ 您可執行下列命令來建立鍵值存放區，並從 Amazon S3 儲存貯體匯入鍵值對。

  ```
  aws cloudfront create-key-value-store \
      --name=keyvaluestore1 \
      --comment="This is my key value store file" \
      --import-source=SourceType=S3,SourceARN=arn:aws:s3:::amzn-s3-demo-bucket1/kvs-input.json
  ```

  **回應**

  ```
  {
      "ETag": "ETVABCEXAMPLE",
      "Location": "https://cloudfront.amazonaws.com/2020-05-31/key-value-store/arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
      "KeyValueStore": {
          "Name": "keyvaluestore1",
          "Id": "8aa76c93-3198-462c-aaf6-example",
          "Comment": "This is my key value store file",
          "ARN": "arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
          "Status": "PROVISIONING",
          "LastModifiedTime": "2024-08-06T22:19:10.813000+00:00"
      }
  }
  ```

------
#### [ API ]

**建立鍵值存放區**

1. 使用 [CloudFront CreateKeyValueStore](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateKeyValueStore.html) 操作。該操作需要幾個參數：
   + 鍵值存放區的 `name`。
   + 包含註解的 `comment` 參數。
   + 可讓您從存放在 Amazon S3 儲存貯體的檔案匯入鍵值對的 `import-source` 參數。您只能在第一次建立鍵值存放區時從檔案匯入。如需檔案結構的相關資訊，請參閱 [鍵值對的檔案格式](kvs-with-functions-create-s3-kvp.md)。

操作回應包含下列資訊：
+ 請求中傳遞的值，包括您指派的名稱。
+ 建立時間等資料。
+ `ETag` (例如 `ETVABCEXAMPLE`) 為包含鍵值存放區名稱的 ARN (例如 `arn:aws:cloudfront::123456789012:key-value-store/keyvaluestore1`)。

  您將使用 `ETag`、ARN 和名稱的某些組合，以程式設計方式處理鍵值存放區。

------

## 鍵值存放區狀態
<a name="key-value-store-status"></a>

您建立鍵值存放區時，資料存放區可能有下列狀態值。


****  

| Value | Description | 
| --- | --- | 
|  **佈建**  |  鍵值存放區已建立，CloudFront 正在處理您指定的資料來源。  | 
|  **備妥**  |  鍵值存放區已建立，CloudFront 已成功處理您指定的資料來源。  | 
|  **匯入失敗**  |  CloudFront 無法處理您指定的資料來源。如果您的檔案格式無效或超過大小限制，就會出現此狀態。如需詳細資訊，請參閱[鍵值對的檔案格式](kvs-with-functions-create-s3-kvp.md)。  | 

# 將鍵值存放區與函數建立關聯。
<a name="kvs-with-functions-associate"></a>

您建立鍵值存放區之後，就可以更新函數，將其與鍵值存放區建立關聯。您必須建立此關聯，才能在該函數中使用該存放區中的鍵值對。適用的規定如下：
+ 一個函數只能有一個鍵值存放區
+ 同一個鍵值存放區可以與多個函數建立關聯

------
#### [ Console ]

**將鍵值存放區與函數建立關聯**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions) 登入 CloudFront 主控台，並選擇**函數**頁面。

1. 選擇函數名稱。

1. 前往**關聯 KeyValueStore** 區段，然後選擇**關聯現有的 KeyValueStore**。

1. 選取函數中包含鍵值對的鍵值存放區，然後選擇**關聯 KeyValueStore**。

   CloudFront 會立即將存放區與該函數建立關聯。您無需儲存函數。

1. 若要指定不同的鍵值存放區，請選擇**更新關聯的 KeyValueStore**，選擇另一個鍵值存放區名稱，然後選擇**關聯 KeyValueStore**。

如需詳細資訊，請參閱[更新函數](update-function.md)。

------
#### [ AWS CLI ]

**將鍵值存放區與函數建立關聯**
+ 您可執行下列命令來更新 `MaxAge` 函數，並與鍵值存放區資源建立關聯。

  ```
  aws cloudfront update-function \
      --name MaxAge \
      --function-config '{"Comment":"Max Age 2 years","Runtime":"cloudfront-js-2.0","KeyValueStoreAssociations":{"Quantity":1,"Items":[{"KeyValueStoreARN":"arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example"}]}}' \
      --function-code fileb://function-max-age-v1.js \
      --if-match ETVABCEXAMPLE
  ```
+ 若要將鍵值存放區與函數建立關聯，請指定 `KeyValueStoreAssociations` 參數和鍵值存放區 ARN。
+ 若要變更關聯，請指定另一個鍵值存放區 ARN。
+ 若要移除關聯，請移除 `KeyValueStoreAssociations` 參數。

如需詳細資訊，請參閱[更新函數](update-function.md)。

------
#### [ API ]

**將鍵值存放區與函數建立關聯**
+ 使用 [UpdateFunction](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateFunction.html) API 操作。如需詳細資訊，請參閱[更新函數](update-function.md)。

------

**備註**  
如果您修改鍵值存放區而不變更鍵值對，或者只修改鍵值存放區中的鍵值對，則不需要再次關聯鍵值存放區。您也不需要重新發佈函數。  
不過我們建議您測試函數，以確認函數是否如預期般運作。如需詳細資訊，請參閱[測試函數](test-function.md)。
您可以檢視使用特定鍵值存放區的所有函數。在 CloudFront 主控台上，選擇鍵值存放區詳細資訊頁面。

# 更新鍵值存放區
<a name="kvs-with-functions-edit"></a>

您更新鍵值存放區時可以變更鍵值對，或變更鍵值存放區和函數之間的關聯。

------
#### [ Console ]

**更新鍵值存放區**

1. 登入 ， AWS 管理主控台 並在位於 的 CloudFront 主控台中開啟**函數**頁面[https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)。

1. 選擇 **KeyValueStores** 索引標籤。

1.  選擇您想要更新的鍵值存放區。
   + 若要更新鍵值對，請選擇**鍵值對**區段中的**編輯**。您可以新增或刪除任何鍵值對。您也可以變更現有鍵值對的值。完成時，請選擇**儲存變更**。
   + 若要更新此鍵值存放區的關聯，請選擇**前往函數**。如需詳細資訊，請參閱[將鍵值存放區與函數建立關聯。](kvs-with-functions-associate.md)。

------
#### [ AWS CLI ]

**更新鍵值存放區**

1. **變更鍵值對**：您可以新增更多鍵值對、刪除一或多個鍵值對，也可以變更現有鍵值對的值。如需詳細資訊，請參閱[使用鍵值資料](kvs-with-functions-kvp.md)。

1. **變更鍵值存放區的函數關聯**：若要更新鍵值存放區的關聯函數，請參閱 [將鍵值存放區與函數建立關聯。](kvs-with-functions-associate.md)。
**提示**  
您將需要鍵值存放區的 ARN。如需詳細資訊，請參閱[獲取鍵值存放區參考資料](kvs-with-functions-get-reference.md)。

------
#### [ API ]

**更新鍵值存放區**

1. **變更鍵值對**：您可以新增更多鍵值對、刪除一或多個鍵值對，也可以變更現有鍵值對的值。如需詳細資訊，請參閱[使用鍵值資料](kvs-with-functions-kvp.md)。

1. **變更鍵值存放區的函數關聯**：若要更新鍵值存放區的關聯函數，請使用 [UpdateFunction](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateFunction.html) API 操作。如需詳細資訊，請參閱[更新函數](update-function.md)。
**提示**  
您將需要鍵值存放區的 ARN。如需詳細資訊，請參閱[獲取鍵值存放區參考資料](kvs-with-functions-get-reference.md)。

------

# 獲取鍵值存放區參考資料
<a name="kvs-with-functions-get-reference"></a>

為了以程式設計方式使用鍵值存放區，您需要 `ETag` 和鍵值存放區的名稱。

若要取得這兩個值，您可以使用 AWS Command Line Interface (AWS CLI) 或 CloudFront API。

------
#### [ AWS CLI ]

**取得鍵值存放區參考資料**

1. 若要傳回鍵值存放區清單，請執行下列命令。尋找您要變更的鍵值存放區名稱。

   ```
   aws cloudfront list-key-value-stores
   ```

1. 從回應中尋找您想要的鍵值存放區名稱。

   **回應**

   ```
   {
       "KeyValueStoreList": {
           "Items": [
               {
                   "Name": "keyvaluestore3",
                   "Id": "37435e19-c205-4271-9e5c-example3",
                   "ARN": "arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example3",
                   "Status": "READY",
                   "LastModifiedTime": "2024-05-08T14:50:18.876000+00:00"
               },
               {
                   "Name": "keyvaluestore2",
                   "Id": "47970d59-6408-474d-b850-example2",
                   "ARN": "arn:aws:cloudfront::123456789012:key-value-store/47970d59-6408-474d-b850-example2",
                   "Status": "READY",
                   "LastModifiedTime": "2024-05-30T21:06:22.113000+00:00"
               },
               {
                   "Name": "keyvaluestore1",
                   "Id": "8aa76c93-3198-462c-aaf6-example",
                   "ARN": "arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
                   "Status": "READY",
                   "LastModifiedTime": "2024-08-06T22:19:30.510000+00:00"
               }
           ]
       }
   }
   ```

1. 執行下列命令，以傳回指定鍵值存放區的 `ETag`。

   ```
   aws cloudfront describe-key-value-store \
       --name=keyvaluestore1
   ```

   **回應**

   ```
   {
       "ETag": "E3UN6WX5RRO2AG",
       "KeyValueStore": {
           "Name": "keyvaluestore1",
           "Id": "8aa76c93-3198-462c-aaf6-example",
           "Comment": "This is an example KVS",
           "ARN": "arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
           "Status": "READY",
           "LastModifiedTime": "2024-08-06T22:19:30.510000+00:00"
       }
   }
   ```

------
#### [ API ]

**取得鍵值存放區參考資料**

1. 使用 [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html) API 操作傳回鍵值存放區清單。尋找您想要變更的鍵值存放區名稱。

1. 使用 [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DescribeKeyValueStore.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DescribeKeyValueStore.html) API 操作，並指定您從上一個步驟傳回的鍵值存放區名稱。

------

回應包括 UUID、鍵值存放區的 ARN 以及鍵值存放區的 `ETag`。
+ `ETag` (例如 `E3UN6WX5RRO2AG`)
+ UUID 為 128 位元 (例如 `8aa76c93-3198-462c-aaf6-example`)
+ ARN 包含 AWS 帳戶 數字、常數 `key-value-store`和 UUID，如下列範例所示：

  `arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example`

如需 `DescribeKeyValueStore` 操作的詳細資訊，請參閱 [關於 CloudFront KeyValueStore](kvs-with-functions-kvp.md#kvs-with-functions-api-describe)。

# 刪除鍵值存放區
<a name="kvs-with-functions-delete"></a>

您可以使用 Amazon CloudFront 主控台或 API 來刪除鍵值存放區。

------
#### [ Console ]

**刪除鍵值存放區**

1. 登入 ， AWS 管理主控台 並在位於 的 CloudFront 主控台中開啟**函數**頁面[https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)。

1. 選擇函數名稱。

1. 在**關聯的 KeyValueStore** 區段下，驗證鍵值存放區是否與函數相關聯。如果是，請選擇**取消關聯 KeyValueStore** 以移除關聯，然後選擇**移除關聯**。

1. 在導覽面板中選擇**函數**頁面，然後選擇 **KeyValueStores** 索引標籤。

1. 選取您要刪除的鍵值存放區，然後選擇**刪除**。

------
#### [ AWS CLI ]

**刪除鍵值存放區**

1. 獲取 `ETag` 和鍵值存放區的名稱。如需詳細資訊，請參閱[獲取鍵值存放區參考資料](kvs-with-functions-get-reference.md)。

1. 驗證鍵值存放區是否與函數相關聯。如果是，將移除關聯。如需這些步驟的詳細資訊，請參閱 [更新函數](update-function.md)。

1. 如果您已取得鍵值存放區的名稱和 `ETag`，且鍵值存放區不再與函數相關聯，就可以將其刪除。

   請執行下列命令來刪除指定的鍵值存放區。

   ```
   aws cloudfront delete-key-value-store \
       --name=keyvaluestore1 \
       --if-match=E3UN6WX5RRO2AG
   ```

------
#### [ API ]

**刪除鍵值存放區**

1. 獲取 `ETag` 和鍵值存放區的名稱。如需詳細資訊，請參閱[獲取鍵值存放區參考資料](kvs-with-functions-get-reference.md)。

1. 驗證鍵值存放區是否與函數相關聯。如果是，將移除關聯。如需這些步驟的詳細資訊，請參閱 [更新函數](update-function.md)。

1. 若要刪除鍵值存放區，請使用 CloudFront [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DeleteKeyValueStore.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DeleteKeyValueStore.html) API 操作。

------

# 鍵值對的檔案格式
<a name="kvs-with-functions-create-s3-kvp"></a>

建立 UTF-8 編碼的檔案時，請使用下列 JSON 格式：

```
{
  "data":[
    {
      "key":"key1",
      "value":"value"
    },
    {
      "key":"key2",
      "value":"value"
    }
  ]
}
```

您的檔案不能包含重複的鍵。如果您在 Amazon S3 儲存貯體中指定了無效檔案，您可以更新檔案以移除任何重複項目，然後再次嘗試建立您的鍵值存放區。

如需詳細資訊，請參閱[建立鍵值存放區](kvs-with-functions-create.md)。

**注意**  
資料來源及其鍵值組的檔案具有以下限制：  
檔案大小 - 5 MB
鍵大小 — 512 個字元
鍵大小 — 1024 個字元

# 使用鍵值資料
<a name="kvs-with-functions-kvp"></a>

本節說明如何將鍵值對新增至現有的鍵值存放區。若要在最初建立鍵值存放區時包含鍵值對，請參閱 [建立鍵值存放區](kvs-with-functions-create.md)。

**Topics**
+ [使用鍵值對 (主控台)](#kvs-with-functions-kvp-using-console)
+ [關於 CloudFront KeyValueStore](#kvs-with-functions-api-describe)
+ [使用鍵值對 (AWS CLI)](#work-with-kvs-cli-keys)
+ [使用鍵值對 (API)](#kvs-with-functions-kvp-using-api)

## 使用鍵值對 (主控台)
<a name="kvs-with-functions-kvp-using-console"></a>

您可使用 CloudFront 主控台處理鍵值對。

**使用鍵值對**

1. 登入 ， AWS 管理主控台 並在位於 的 CloudFront 主控台中開啟**函數**頁面[https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)。

1. 選擇 **KeyValueStores** 索引標籤。

1. 選擇您想要變更的鍵值存放區。

1. 在**鍵值對**區段中選擇**編輯**。

1. 您可以新增鍵值對、刪除鍵值對，或變更現有鍵值對的值。

1. 完成時，請選擇**儲存變更**。

## 關於 CloudFront KeyValueStore
<a name="kvs-with-functions-api-describe"></a>

**提示**  
CloudFront KeyValueStore API 是使用 Signature 第 4A 版 (SigV4A) 進行身分驗證的全域服務。使用臨時憑證搭配 SigV4A 需要第 2 版工作階段記號。如需詳細資訊，請參閱[搭配 CloudFront KeyValueStore API 使用臨時憑證](cloudfront-function-restrictions.md#regional-endpoint-for-key-value-store)。

如果您使用 AWS Command Line Interface (AWS CLI) 或自己的程式碼來呼叫 CloudFront KeyValueStore API，請參閱下列各節。

您使用鍵值存放區及其鍵值對時，您呼叫的服務取決於您的使用案例：
+ 若要使用*現有*鍵值存放區的鍵值對，請使用 CloudFront KeyValueStore 服務。
+ 若要在*最初*建立鍵值存放區時在其中包含一些鍵值對，請使用 CloudFront 服務。

CloudFront API 和 CloudFront KeyValueStore API 都具有 `DescribeKeyValueStore` 操作。您會依據不同原因呼叫這兩項服務。若要瞭解其中差異，請參閱下表。


|  | CloudFront DescribeKeyValueStore API | CloudFront KeyValueStore DescribeKeyValueStore API | 
| --- | --- | --- | 
| 關於鍵值存放區的資料 |  傳回資料，例如狀態和上次修改鍵值存放區的日期。  |  傳回有關儲存資源*內容*的資料：存放區中的鍵值對，以及內容的大小。  | 
| 識別鍵值存放區的資料 |  傳回鍵值存放區的 `ETag`、UUID 和 ARN。  |  傳回鍵值存放區的 `ETag` 和 ARN。  | 

**備註**  
每個 DescribeKeyValueStore 操作會傳回*不同的* `ETag`。`ETags` 不可互換。
您呼叫 API 操作以完成動作時，必須從適當的 API 指定 `ETag`。例如在 CloudFront KeyValueStore 的 [DeleteKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DeleteKey.html) 操作中，您要指定從 CloudFront KeyValueStore [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DescribeKeyValueStore.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DescribeKeyValueStore.html) 操作傳回的 `ETag`。
您使用 CloudFront KeyValueStore 調用 CloudFront Functions 時，鍵值存放區的值在調用函數期間不會更新或變更。更新會在函數調用之間進行處理。

## 使用鍵值對 (AWS CLI)
<a name="work-with-kvs-cli-keys"></a>

您可以針對 CloudFront KeyValueStore 執行下列 AWS Command Line Interface 命令。

**Contents**
+ [列出鍵值對](#kvs-cli-list-keys)
+ [取得鍵值對](#kvs-cli-get-keys)
+ [描述鍵值存放區](#kvs-cli-describe-keys)
+ [建立鍵值對](#kvs-cli-create-keys)
+ [刪除鍵值對](#kvs-cli-delete-keys)
+ [更新鍵值對](#kvs-cli-update-key)

### 列出鍵值對
<a name="kvs-cli-list-keys"></a>

若要列出鍵值存放區中的鍵值對，請執行下列命令。

```
aws cloudfront-keyvaluestore list-keys \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**回應**

```
{
    "Items": [
        {
            "Key": "key1",
            "Value": "value1"
        }
    ]
}
```

### 取得鍵值對
<a name="kvs-cli-get-keys"></a>

若要取得鍵值存放區中的鍵值對，請執行下列命令。

```
aws cloudfront-keyvaluestore get-key \
    --key=key1 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**回應**

```
{
    "Key": "key1",
    "Value": "value1",
    "ItemCount": 1,
    "TotalSizeInBytes": 11
}
```

### 描述鍵值存放區
<a name="kvs-cli-describe-keys"></a>

若要描述鍵值存放區，請執行下列命令。

```
aws cloudfront-keyvaluestore describe-key-value-store \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**回應**

```
{
    "ETag": "KV1F83G8C2ARO7P",
    "ItemCount": 1,
    "TotalSizeInBytes": 11,
    "KvsARN": "arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example",
    "Created": "2024-05-08T07:48:45.381000-07:00",
    "LastModified": "2024-08-05T13:50:58.843000-07:00",
    "Status": "READY"
}
```

### 建立鍵值對
<a name="kvs-cli-create-keys"></a>

若要在鍵值存放區建立鍵值對，請執行下列命令。

```
aws cloudfront-keyvaluestore put-key \
    --if-match=KV1PA6795UKMFR9 \
    --key=key2 \
    --value=value2 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**回應**

```
{
    "ETag": "KV13V1IB3VIYZZH",
    "ItemCount": 3,
    "TotalSizeInBytes": 31
}
```

### 刪除鍵值對
<a name="kvs-cli-delete-keys"></a>

若要刪除鍵值對，請執行下列命令。

```
aws cloudfront-keyvaluestore delete-key \
    --if-match=KV13V1IB3VIYZZH \
    --key=key1 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**輸出**

```
{
    "ETag": "KV1VC38T7YXB528",
    "ItemCount": 2,
    "TotalSizeInBytes": 22
}
```

### 更新鍵值對
<a name="kvs-cli-update-key"></a>

您可以使用 `update-keys` 命令來更新多個鍵值對。例如若要刪除現有鍵值對並建立另一個，請執行下列命令。

```
aws cloudfront-keyvaluestore update-keys \
    --if-match=KV2EUQ1WTGCTBG2 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example \
    --deletes '[{"Key":"key2"}]' \
    --puts '[{"Key":"key3","Value":"value3"}]'
```

**回應**

```
{
    "ETag": "KV3AEGXETSR30VB",
    "ItemCount": 3,
    "TotalSizeInBytes": 28
}
```

## 使用鍵值對 (API)
<a name="kvs-with-functions-kvp-using-api"></a>

您可遵循本節說明以程式設計方式使用鍵值對。

**Contents**
+ [獲取鍵值存放區參考資料](#kvs-with-functions-api-ref)
+ [變更鍵值存放區中的鍵值對](#kvs-with-functions-api-actions)
+ [CloudFront KeyValueStore 的範例程式碼](#example-code-key-value-store)

### 獲取鍵值存放區參考資料
<a name="kvs-with-functions-api-ref"></a>

您使用 CloudFront KeyValueStore API 呼叫寫入操作時，需要指定鍵值存放區的 ARN 和 `ETag`。若要取得此資料，請依下列步驟執行：

**取得鍵值存放區參考資料**

1. 使用 [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html) API 操作取得鍵值存放區清單。尋找您想要變更的鍵值存放區。

1. 使用 [CloudFrontKeyValueStore DescribeKeyValueStore API 操作](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DescribeKeyValueStore.html)，並指定上一個步驟的鍵值存放區。

   回應包括鍵值存放區的 ARN 和 `ETag`。
   + ARN 包含 AWS 帳戶 數字、常數 `key-value-store`和 UUID，例如下列範例：

     `arn:aws:cloudfront::123456789012:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111`
   + `ETag` 如下列範例所示：

     `ETVABCEXAMPLE2`

### 變更鍵值存放區中的鍵值對
<a name="kvs-with-functions-api-actions"></a>

您可以指定包含所需更新鍵值對的鍵值存放區。

請參閱下列 CloudFront KeyValueStore API 操作：
+ [CloudFrontKeyValueStore DeleteKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DeleteKey.html)：刪除鍵值對
+ [CloudFrontKeyValueStore GetKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_GetKey.html)：傳回鍵值對
+ [CloudFrontKeyValueStore ListKeys](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_ListKeys.html)：傳回鍵值對清單 
+ [CloudFrontKeyValueStore PutKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_PutKey.html)：您可以執行下列任務：
  + 指定新的鍵名稱及值，以在鍵值存放區中建立新的鍵值對。
  + 指定現有鍵名稱及新的鍵值，以在現有鍵值對中設定不同的值。
+ [CloudFrontKeyValueStore UpdateKeys](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_UpdateKeys.html)：您可以在一個「全有或全無」操作中執行下列其中一個或多個動作：
  + 刪除一或多個鍵值對
  + 建立一或多個新的鍵值對
  + 在一個或多個現有鍵值對中設定不同的值

### CloudFront KeyValueStore 的範例程式碼
<a name="example-code-key-value-store"></a>

**Example**  
下列程式碼示範如何呼叫鍵值存放區的 `DescribeKeyValueStore` API 操作。  

```
const {
  CloudFrontKeyValueStoreClient,
  DescribeKeyValueStoreCommand,
} = require("@aws-sdk/client-cloudfront-keyvaluestore");

require("@aws-sdk/signature-v4-crt");

(async () => {
  try {
    const client = new CloudFrontKeyValueStoreClient({
      region: "us-east-1"
    });
    const input = {
      KvsARN: "arn:aws:cloudfront::123456789012:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
    };
    const command = new DescribeKeyValueStoreCommand(input);

    const response = await client.send(command);
  } catch (e) {
    console.log(e);
  }
})();
```