

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

# 使用 Rust 建置 Lambda 函數
<a name="lambda-rust"></a>

由於 Rust 會編譯成原生程式碼，因此您不需要專用的執行期即可在 Lambda 上執行 Rust 程式碼。反之，請使用 [Rust 執行期用戶端](https://github.com/aws/aws-lambda-rust-runtime)在本機建置您的專案，然後使用[僅限作業系統的執行期](runtimes-provided.md)將其部署至 Lambda。當您使用僅限作業系統的執行時間時，Lambda 會自動將作業系統保持在最新修補程式的狀態。

**適用於 Rust 的工具和程式庫**
+ [適用於 Rust 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/getting-started.html)：適用於 Rust 的 AWS SDK 提供 Rust APIs來與 Amazon Web Services 基礎設施服務互動。
+  [Lambda 的 Rust 執行期用戶端](https://github.com/aws/aws-lambda-rust-runtime)：Rust 執行期用戶端可讓您輕鬆地執行以 Rust 撰寫的 Lambda 函數。
+ [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html)：這是 Cargo 命令列工具的第三方開放原始碼延伸，可簡化 Rust Lambda 函數的建置和部署。
+ [Lambda HTTP](https://github.com/aws/aws-lambda-rust-runtime/tree/main/lambda-http)：此程式庫提供一個包裝程式來處理 HTTP 事件。
+  [Lambda 延伸](https://github.com/aws/aws-lambda-rust-runtime/tree/main/lambda-extension)：此程式庫可支援使用 Rust 撰寫的 Lambda 延伸。
+ [AWS Lambda 事件](https://crates.io/crates/aws_lambda_events)：此程式庫提供常見事件來源整合的類型定義。

**Rust 的範本 Lambda 應用程式**
+ [基本 Lambda 函數](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/basic-lambda)：顯示如何處理基本事件的 Rust 函數。
+ [具有錯誤處理功能的 Lambda 函數](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/basic-error-handling)：示範如何在 Lambda 中處理自訂 Rust 錯誤的 Rust 函數。
+ [含有共用資源的 Lambda 函數](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/basic-shared-resource)：可在建立 Lambda 函數之前初始化共用資源的 Rust 專案。
+ [Lambda HTTP 事件](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/http-basic-lambda)：處理 HTTP 事件的 Rust 函數。
+ [帶有 CORS 標頭的 Lambda HTTP 事件](https://github.com/aws/aws-lambda-rust-runtime/blob/main//examples/http-cors)：使用 Tower 插入 CORS 標頭的 Rust 函數。
+ [Lambda REST API](https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/http-axum-diesel)：使用 Axum 和 Diesel 連線至 PostgreSQL 資料庫的 REST API。
+ [Serverless Rust 示範](https://github.com/aws-samples/serverless-rust-demo/)：Rust 專案，顯示 Lambda 的 Rust 程式庫、記錄、環境變數和 AWS SDK 的使用方式。
+ [基本 Lambda 延伸](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/extension-basic)：顯示如何處理基本延伸事件的 Rust 延伸。
+ [Lambda 日誌 Amazon Data Firehose 延伸](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/extension-logs-kinesis-firehose)：顯示如何將 Lambda 日誌傳送至 Firehose 的 Rust 延伸。

**Topics**
+ [

# 在 Rust 中定義 Lambda 函式處理常式
](rust-handler.md)
+ [

# 使用 Lambda 內容物件擷取 Rust 函數資訊
](rust-context.md)
+ [

# 使用 Rust 處理 HTTP 事件
](rust-http-events.md)
+ [

# 使用 .zip 封存檔部署 Rust Lambda 函數
](rust-package.md)
+ [

# 使用 Rust Lambda 函式的層
](rust-layers.md)
+ [

# 記錄和監控 Rust Lambda 函數
](rust-logging.md)

# 在 Rust 中定義 Lambda 函式處理常式
<a name="rust-handler"></a>

Lambda 函數*處理常式*是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時，Lambda 會執行處理常式方法。函數會執行，直到處理常式傳回回應、結束或逾時為止。

本頁介紹了如何在 Rust 中使用 Lambda 函式處理常式，包括專案初始化、命名慣例及最佳實務。本頁還提供了一個 Rust Lambda 函式範例，該函式會取得訂單的相關資訊、產生文字檔案收據，並將此檔案放入 Amazon Simple Storage Service (S3) 儲存貯體。如需有關編寫函式後如何部署的詳細資訊，請參閱[使用 .zip 封存檔部署 Rust Lambda 函數](rust-package.md)。

**Topics**
+ [

## 設定 Rust 處理常式專案
](#rust-handler-setup)
+ [

## Lambda 函式程式碼範例
](#rust-example-code)
+ [

## Rust 處理常式的有效類別定義
](#rust-handler-signatures)
+ [

## 處理常式命名慣例
](#rust-example-naming)
+ [

## 定義和存取輸入事件物件
](#rust-handler-input)
+ [

## 存取和使用 Lambda 內容物件
](#rust-example-context)
+ [

## 在處理常式 適用於 Rust 的 AWS SDK 中使用
](#rust-example-sdk-usage)
+ [

## 存取環境變數
](#rust-example-envvars)
+ [

## 使用共用狀態
](#rust-shared-state)
+ [

## Rust Lambda 函數的程式碼最佳實務
](#rust-best-practices)

## 設定 Rust 處理常式專案
<a name="rust-handler-setup"></a>

使用 Rust 開發 Lambda 函式時，流程涉及編寫程式碼、編譯程式碼，以及將編譯的成品部署至 Lambda。在 Rust 中設定 Lambda 處理常式專案，最簡單的方法便是使用 [AWS Lambda Runtime for Rust](https://github.com/aws/aws-lambda-rust-runtime)。雖然名稱相同，但 Rust 的 AWS Lambda 執行期與適用於 Python、Java 或 Node.js 的 Lambda 中的執行期並不相同。反之， AWS Lambda Runtime for Rust 是一種木箱 (`lambda_runtime`)，支援在 Rust 中寫入 Lambda 函數並連接 AWS Lambda的執行環境。

使用下列命令來安裝 [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html)，這是 Cargo 命令列工具的第三方開放原始碼延伸，可簡化 Rust Lambda 函數的建置和部署：

```
cargo install cargo-lambda
```

成功安裝 `cargo-lambda` 之後，使用下列命令來初始化新的 Rust Lambda 函式處理常式專案：

```
cargo lambda new example-rust
```

當您執行此命令時，命令列介面 (CLI) 會詢問幾個有關 Lambda 函式的問題：
+ **HTTP 函式**：如果您想要透過 [API Gateway](services-apigateway.md) 或[函式 URL](urls-configuration.md) 調用函式，請回答**是**。否則，請回答**否**。在本頁的範例程式碼中，由於我們使用自訂 JSON 事件來調用函式，因此回答**否**。
+ **事件類型**：如果您想要使用預先定義的事件結構來調用函式，請選取正確的預期事件類型。否則，請將此選項保留空白。在本頁的範例程式碼中，由於我們使用自訂 JSON 事件來調用函式，因此將此選項保留空白。

命令成功執行後，輸入專案的主目錄：

```
cd example-rust
```

此命令會在 `src` 目錄中產生 `generic_handler.rs` 檔案和 `main.rs` 檔案。`generic_handler.rs` 可用於自訂泛型事件處理常式。`main.rs` 檔案包含應用程式的主要邏輯。`Cargo.toml` 檔案包含有關套件的中繼資料，並列出其外部相依項。

## Lambda 函式程式碼範例
<a name="rust-example-code"></a>

以下 Rust Lambda 函式程式碼範例會取得訂單的相關資訊、產生文字檔案收據，並將此檔案放入 Amazon S3 儲存貯體。

**Example `main.rs` Lambda 函數**  

```
use aws_sdk_s3::{Client, primitives::ByteStream};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::env;

#[derive(Deserialize, Serialize)]
struct Order {
    order_id: String,
    amount: f64,
    item: String,
}

async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
    let payload = event.payload;

    // Deserialize the incoming event into Order struct
    let order: Order = serde_json::from_value(payload)?;

    let bucket_name = env::var("RECEIPT_BUCKET")
        .map_err(|_| "RECEIPT_BUCKET environment variable is not set")?;

    let receipt_content = format!(
        "OrderID: {}\nAmount: ${:.2}\nItem: {}",
        order.order_id, order.amount, order.item
    );
    let key = format!("receipts/{}.txt", order.order_id);

    let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
    let s3_client = Client::new(&config);

    upload_receipt_to_s3(&s3_client, &bucket_name, &key, &receipt_content).await?;

    Ok("Success".to_string())
}

async fn upload_receipt_to_s3(
    client: &Client,
    bucket_name: &str,
    key: &str,
    content: &str,
) -> Result<(), Error> {
    client
        .put_object()
        .bucket(bucket_name)
        .key(key)
        .body(ByteStream::from(content.as_bytes().to_vec()))  // Fixed conversion
        .content_type("text/plain")
        .send()
        .await?;

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    run(service_fn(function_handler)).await
}
```

此 `main.rs` 檔案包含以下程式碼區段：
+ `use` 陳述式：用於匯入 Lambda 函式所需的 Rust Crate 與方法。
+ `#[derive(Deserialize, Serialize)]`：定義此 Rust 結構體中預期輸入事件的結構。
+ `async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>`：這是**主要處理常式方法**，其中包含應用程式的主要邏輯。
+ `async fn upload_receipt_to_s3 (...)`：此為主要 `function_handler` 方法所參照的協助程式方法。
+ `#[tokio::main]`：此為標記 Rust 程式進入點的巨集。其還會設定 [Tokio 執行時期](https://docs.rs/tokio/latest/tokio/runtime/index.html)，允許 `main()` 方法使用 `async`/`await` 並以非同步方式執行。
+ `async fn main() -> Result<(), Error>`：`main()` 函式是程式碼的進入點。我們會在其中將 `function_handler` 指定為主要處理常式方法。

### Cargo.toml 檔案範例
<a name="rust-cargo-toml"></a>

下列 `Cargo.toml` 為此函式的配套檔案。

```
[package]
name = "example-rust"
version = "0.1.0"
edition = "2024"

[dependencies]
aws-config = "1.5.18"
aws-sdk-s3 = "1.78.0"
lambda_runtime = "0.13.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
```

若要讓此函式正常運作，其[執行角色](lambda-intro-execution-role.md)必須允許 `s3:PutObject` 動作。此外，請確保定義 `RECEIPT_BUCKET` 環境變數。成功調用後，Amazon S3 儲存貯體應包含收據檔案。

## Rust 處理常式的有效類別定義
<a name="rust-handler-signatures"></a>

大多數情況下，在 Rust 中定義的 Lambda 處理常式簽章將具有下列格式：

```
async fn function_handler(event: LambdaEvent<T>) -> Result<U, Error>
```

對於此處理常式：
+ 此處理常式名稱為 `function_handler`。
+ 處理常式的單一輸入參數為 event，類型為 `LambdaEvent<T>`。
  + `LambdaEvent` 是來自 `lambda_runtime` 套件的包裝函式。借助此包裝函式，您可以存取內容物件，其中包含 Lambda 特定的中繼資料，例如調用的請求 ID。
  + `T` 是反序列化事件類型。例如，這可以是 `serde_json::Value`，允許處理常式接收所有泛型 JSON 輸入。或者，如果函式需要預先定義的特定輸入類型，這可以是 `ApiGatewayProxyRequest` 等類型。
+ 處理常式的傳回類型為 `Result<U, Error>`。
  + `U` 是反序列化輸出類型。`U` 必須實作 `serde::Serialize` 特徵，Lambda 才能將傳回值轉換為 JSON 格式。舉例而言，`U` 可以是簡單類型，例如 `String`、`serde_json::Value` 或自訂結構體 (只要實作了 `Serialize`)。當程式碼到達 Ok(U) 陳述式時，表示執行成功，且函式會傳回類型為 `U` 的值。
  + 當程式碼遇到錯誤 (即 `Err(Error)`) 時，函式會在 Amazon CloudWatch 中記錄錯誤，並傳回類型為 `Error` 的錯誤回應。

在我們的範例中，處理常式簽章如下所示：

```
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>
```

其他有效的處理常式簽章將會具有下列功能：
+ 省略 `LambdaEvent` 包裝函式：如果省略 `LambdaEvent`，則會失去函式中 Lambda 內容物件的存取權。以下為此類簽章的範例：

  ```
  async fn handler(event: serde_json::Value) -> Result<String, Error>
  ```
+ 使用單位類型作為輸入：對於 Rust，您可以使用單位類型來表示空白輸入。這通常用於具有定期排程調用的函式。以下為此類簽章的範例：

  ```
  async fn handler(_: ()) -> Result<Value, Error>
  ```

## 處理常式命名慣例
<a name="rust-example-naming"></a>

Rust 中的 Lambda 處理常式沒有嚴格的命名限制。雖然您可以為處理常式使用任何名稱，但 Rust 中的函式名稱通常採用 `snake_case`。

對於較小的應用程式，例如在此範例中，您可以使用單一的 `main.rs` 檔案來包含所有程式碼。對於較大的專案，`main.rs` 應該包含函式的進入點，但您可透過額外的檔案將程式碼拆分為邏輯模組。例如，您可能擁有下列檔案結構：

```
/example-rust
│── src/
│   ├── main.rs        # Entry point
│   ├── handler.rs     # Contains main handler
│   ├── services.rs    # [Optional] Back-end service calls
│   ├── models.rs      # [Optional] Data models
│── Cargo.toml
```

## 定義和存取輸入事件物件
<a name="rust-handler-input"></a>

JSON 是 Lambda 函數最常見的標準輸入格式。在此範例中，函數預期輸入類似以下內容：

```
{
    "order_id": "12345",
    "amount": 199.99,
    "item": "Wireless Headphones"
}
```

在 Rust 中，您可透過結構體定義預期輸入事件的結構。在此範例中，我們透過定義以下結構體來表示 `Order`：

```
#[derive(Deserialize, Serialize)]
struct Order {
    order_id: String,
    amount: f64,
    item: String,
}
```

此 struct 符合預期的輸入形狀。在此範例中，`#[derive(Deserialize, Serialize)]` 巨集會自動產生用於序列化和反序列化的程式碼。這意味著我們可透過 `serde_json::from_value()` 方法，將泛型輸入 JSON 類型反序列化至結構體中。這在處理常式的前幾行中得以曾現：

```
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
    let payload = event.payload;

    // Deserialize the incoming event into Order struct
    let order: Order = serde_json::from_value(payload)?;
    ...
}
```

然後，您可以存取該物件的欄位。例如，使用 `order_id` 可以從原始輸入擷取 `order.order_id` 的值。

### 預先定義的輸入事件類型
<a name="rust-input-event-types"></a>

`aws_lambda_events` 套件中有許多預先定義的可用輸入事件類型。例如，若要使用 API Gateway 調用函式，需包含下列匯入：

```
use aws_lambda_events::event::apigw::ApiGatewayProxyRequest;
```

然後，確保主要處理常式使用下列簽章：

```
async fn handler(event: LambdaEvent<ApiGatewayProxyRequest>) -> Result<String, Error> {
    let body = event.payload.body.unwrap_or_default();
    ...
}
```

如需有關其他預先定義輸入事件類型的詳細資訊，請參閱 [aws\$1lambda\$1events crate](https://crates.io/crates/aws_lambda_events)。

## 存取和使用 Lambda 內容物件
<a name="rust-example-context"></a>

Lambda [內容物件](rust-context.md) 包含有關調用、函數以及執行環境的資訊。在 Rust 中，`LambdaEvent` 包裝函式包含內容物件。例如，您可以使用內容物件，透過下列程式碼擷取目前調用的請求 ID：

```
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
    let request_id = event.context.request_id;
    ...
}
```

如需內容物件的詳細資訊，請參閱[使用 Lambda 內容物件擷取 Rust 函數資訊](rust-context.md)。

## 在處理常式 適用於 Rust 的 AWS SDK 中使用
<a name="rust-example-sdk-usage"></a>

通常，您將使用 Lambda 函數與其他 AWS 資源互動或進行更新。與這些資源互動的最簡單方法便是使用 [適用於 Rust 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/welcome.html)。

若要將 SDK 相依項新增至函式，請在 `Cargo.toml` 檔案中納入這些相依相。建議僅新增函式所需的程式庫。在先前的範例程式碼中，我們使用了 `aws_sdk_s3::Client`。在 `Cargo.toml` 檔案中，您可以透過在 `[dependencies]` 區段下新增以下行來納入此相依項：

```
aws-sdk-s3 = "1.78.0"
```

**注意**  
這可能並非最新版本。請為應用程式選擇適當的版本。

然後，直接在程式碼中匯入相依項：

```
use aws_sdk_s3::{Client, primitives::ByteStream};
```

隨後，範例程式碼會初始化 Amazon S3 用戶端，如下所示：

```
let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let s3_client = Client::new(&config);
```

初始化 SDK 用戶端之後，您可以使用它來與其他 AWS 服務互動。範例程式碼會在 `upload_receipt_to_s3` 協助程式函式中呼叫 Amazon S3 `PutObject` API。

## 存取環境變數
<a name="rust-example-envvars"></a>

在處理常式程式碼中，您可以使用 `env::var` 方法來引用任何[環境變數](configuration-envvars.md)。在此範例中，我們使用以下程式碼來參考定義的 `RECEIPT_BUCKET` 環境變數：

```
let bucket_name = env::var("RECEIPT_BUCKET")
    .map_err(|_| "RECEIPT_BUCKET environment variable is not set")?;
```

## 使用共用狀態
<a name="rust-shared-state"></a>

您可以宣告獨立於 Lambda 函數處理常式程式碼的共用變數。這些變數可協助您在函數接收任何事件之前在 [初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib) 過程中載入狀態資訊。例如，您可以透過更新 `main` 函式和處理常式簽章，將本頁的程式碼修改為在初始化 Amazon S3 用戶端時使用共用狀態：

```
async fn function_handler(client: &Client, event: LambdaEvent<Value>) -> Result<String, Error> {
    ...
    upload_receipt_to_s3(client, &bucket_name, &key, &receipt_content).await?;
    ...
}

...
      
#[tokio::main]
async fn main() -> Result<(), Error> {
    let shared_config = aws_config::from_env().load().await;
    let client = Client::new(&shared_config);
    let shared_client = &client;
    lambda_runtime::run(service_fn(move |event: LambdaEvent<Request>| async move {
        handler(&shared_client, event).await
    }))
    .await
```

## Rust Lambda 函數的程式碼最佳實務
<a name="rust-best-practices"></a>

請遵循下列清單中的準則，在建置 Lambda 函數時使用最佳編碼實務：
+ **區隔 Lambda 處理常式與您的核心邏輯。**能允許您製作更多可測單位的函式。
+ **最小化依存項目的複雜性。**偏好更簡易的框架，其可快速在[執行環境](lambda-runtime-environment.md)啟動時載入。
+ **將部署套件最小化至執行時間所必要的套件大小。**這能減少您的部署套件被下載與呼叫前解壓縮的時間。

**請利用執行環境重新使用來改看函式的效能。**在函式處理常式之外初始化 SDK 用戶端和資料庫連線，並在本機快取 `/tmp` 目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。

若要避免叫用間洩漏潛在資料，請不要使用執行環境來儲存使用者資料、事件，或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態，請考慮為每個使用者建立個別函式或個別函式版本。

**使用 Keep-Alive 指令維持持續連線的狀態。**Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線，請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例，請參閱[在 Node.js 中重複使用 Keep-Alive 的連線](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。

**使用[環境變數](configuration-envvars.md)將操作參數傳遞給您的函數。**例如，如果您正在寫入到 Amazon S3 儲存貯體，而非對您正在寫入的儲存貯體名稱進行硬式編碼，請將儲存貯體名稱設定為環境變數。

**避免在 Lambda 函數中使用遞迴調用**，其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量，當更新程式碼時，請立刻將函數的預留並行設為 `0`，以調節對函數的所有調用。

**請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API**。對於 AWS Lambda 受管執行期，Lambda 會定期將安全性和功能更新套用至 Lambda 的內部 APIs。這些內部 API 更新可能是向後不相容的，這會導致意外結果，例如若您的函數依賴於這些非公有 API，則叫用失敗。請參閱 [API 參考](https://docs.aws.amazon.com/lambda/latest/api/welcome.html)查看公開可用 API 的清單。

**撰寫等冪程式碼。**為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊，請參閱 [How do I make my Lambda function idempotent?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/) (如何讓 Lambda 函數等冪？)。

# 使用 Lambda 內容物件擷取 Rust 函數資訊
<a name="rust-context"></a>

當 Lambda 執行您的函數時，其會將內容物件新增至[處理常式](rust-handler.md)接收的 LambdaEvent。此物件提供的各項屬性包含了有關叫用、函式以及執行環境的資訊。

**內容屬性**
+  `request_id`：Lambda 服務產生的 AWS 請求 ID。
+  `deadline`：目前叫用的執行期限，以毫秒為單位。
+  `invoked_function_arn`：被叫用之 Lambda 函數的 Amazon Resource Name (ARN)。
+  `xray_trace_id`：目前調用的 AWS X-Ray 追蹤 ID。
+  `client_content`：由 AWS 行動 SDK 傳送的用戶端內容物件。除非使用 AWS 行動 SDK 叫用 函數，否則此欄位為空白。
+  `identity`：叫用該函數的 Amazon Cognito 身分。除非使用 Amazon Cognito 身分集區發出的 AWS 憑證對 Lambda API 進行叫用請求，否則此欄位為空。
+  `env_config`：來自本機環境變數的 Lambda 函數組態。此屬性包括諸如函數名稱、記憶體分配、版本和日誌串流等資訊。

## 存取叫用內容資訊
<a name="rust-context-invoke"></a>

Lambda 函數有權存取有關其環境和叫用請求的中繼資料。函數處理常式接收的 `LambaEvent` 物件包含 `context` 中繼資料：

```
use lambda_runtime::{service_fn, LambdaEvent, Error};
use serde_json::{json, Value};

async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    let invoked_function_arn = event.context.invoked_function_arn;
    Ok(json!({ "message": format!("Hello, this is function {invoked_function_arn}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}
```

# 使用 Rust 處理 HTTP 事件
<a name="rust-http-events"></a>

Amazon API Gateway API、Application Load Balancer 以及 [Lambda 函數 URL](urls-configuration.md) 可將 HTTP 事件傳送至 Lambda。您可以使用來自 crates.io 的 [aws\$1lambda\$1events](https://crates.io/crates/aws_lambda_events) 套件來處理來自這些來源的事件。

**Example – 處理 API Gateway 代理請求**  
注意下列事項：  
+ `use aws_lambda_events::apigw::{ApiGatewayProxyRequest, ApiGatewayProxyResponse}`：[aws\$1lambda\$1events](https://crates.io/crates/aws-lambda-events) 套件包含許多 Lambda 事件。為了減少編譯時間，請使用功能標誌來激活所需的事件。範例：`aws_lambda_events = { version = "0.8.3", default-features = false, features = ["apigw"] }`。
+ `use http::HeaderMap`：此匯入要求您將 [http](https://crates.io/crates/http) 套件新增到相依項。

```
use aws_lambda_events::apigw::{ApiGatewayProxyRequest, ApiGatewayProxyResponse};
use http::HeaderMap;
use lambda_runtime::{service_fn, Error, LambdaEvent};

async fn handler(
    _event: LambdaEvent<ApiGatewayProxyRequest>,
) -> Result<ApiGatewayProxyResponse, Error> {
    let mut headers = HeaderMap::new();
    headers.insert("content-type", "text/html".parse().unwrap());
    let resp = ApiGatewayProxyResponse {
        status_code: 200,
        multi_value_headers: headers.clone(),
        is_base64_encoded: false,
        body: Some("Hello AWS Lambda HTTP request".into()),
        headers,
    };
    Ok(resp)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}
```

[Lambda 的 Rust 執行期用戶端](https://github.com/aws/aws-lambda-rust-runtime)也提供這些事件類型的抽象表示，讓您可以使用原生 HTTP 類型，而不論是哪個服務傳送事件。下列程式碼等同於前一個範例，而且可直接使用 Lambda 函數 URL、Application Load Balancer 和 API Gateway。

**注意**  
該 [lambda\$1http](https://crates.io/crates/lambda_http) 套件使用下面的 [lambda\$1runtime](https://crates.io/crates/lambda_runtime) 套件。不必單獨匯入 `lambda_runtime`。

**Example – 處理 HTTP 請求**  

```
use lambda_http::{service_fn, Error, IntoResponse, Request, RequestExt, Response};

async fn handler(event: Request) -> Result<impl IntoResponse, Error> {
    let resp = Response::builder()
        .status(200)
        .header("content-type", "text/html")
        .body("Hello AWS Lambda HTTP request")
        .map_err(Box::new)?;
    Ok(resp)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_http::run(service_fn(handler)).await
}
```

如需如何使用 的另一個範例`lambda_http`，請參閱 AWS Labs GitHub 儲存庫上的 [http-axum 程式碼範例](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/http-axum/src/main.rs)。

**Rust 的 HTTP Lambda 事件範例**
+ [Lambda HTTP 事件](https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/http-basic-lambda)：處理 HTTP 事件的 Rust 函數。
+ [帶有 CORS 標頭的 Lambda HTTP 事件](https://github.com/aws/aws-lambda-rust-runtime/blob/main/examples/http-cors)：使用 Tower 插入 CORS 標頭的 Rust 函數。
+ [含有共用資源的 Lambda HTTP 事件](https://github.com/aws/aws-lambda-rust-runtime/tree/main/examples/basic-shared-resource)：一個 Rust 函數，它使用在建立函數處理常式之前初始化的共用資源。

# 使用 .zip 封存檔部署 Rust Lambda 函數
<a name="rust-package"></a>

此頁面說明如何編譯 Rust 函數，然後使用 AWS Lambda [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html) 將編譯的二進位檔部署至 。它還顯示如何使用 AWS Command Line Interface 和 AWS Serverless Application Model CLI 部署編譯的二進位檔。

**Topics**
+ [

## 先決條件
](#rust-package-prerequisites)
+ [

## 在 macOS、Windows 或 Linux 上建置 Rust 函數
](#rust-package-build)
+ [

## 使用 Cargo Lambda 部署 Rust 函數二進位檔
](#rust-deploy-cargo)
+ [

## 使用 Cargo Lambda 叫用您的 Rust 函數
](#rust-invoke-function)

## 先決條件
<a name="rust-package-prerequisites"></a>
+ [Rust](https://www.rust-lang.org/tools/install)
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)

## 在 macOS、Windows 或 Linux 上建置 Rust 函數
<a name="rust-package-build"></a>

下列步驟示範如何使用 Rust 為第一個 Lambda 函數建立專案，並使用 [Cargo Lambda](https://www.cargo-lambda.info/) 編譯專案，這是 Cargo 命令列工具的第三方開放原始碼延伸模組，可簡化 Rust Lambda 函數的建置和部署。

1. 安裝 [Cargo Lambda](https://www.cargo-lambda.info/guide/what-is-cargo-lambda.html)，這是 Cargo 命令列工具的第三方開放原始碼延伸，可簡化 Rust Lambda 函數的建置和部署：

   ```
   cargo install cargo-lambda
   ```

   如需其他安裝選項，請參閱 Cargo Lambda 文件中的[安裝](https://www.cargo-lambda.info/guide/installation.html)。

1. 建立套件結構。此命令會在 `src/main.rs` 中建立一些基礎函數程式碼。可以使用此程式碼進行測試，也可以將其替換為您自己的程式碼。

   ```
   cargo lambda new my-function
   ```

1. 在套件的根目錄中，執行 [build](https://www.cargo-lambda.info/commands/build.html) 子命令來編譯函數中的程式碼。

   ```
   cargo lambda build --release
   ```

   （選用） 如果您想要在 Lambda 上使用 AWS Graviton2，請新增 `--arm64`旗標來編譯 ARM CPUs 的程式碼。

   ```
   cargo lambda build --release --arm64
   ```

1. 部署 Rust 函數之前，請在機器上設定 AWS 登入資料。

   ```
   aws configure
   ```

## 使用 Cargo Lambda 部署 Rust 函數二進位檔
<a name="rust-deploy-cargo"></a>

使用 [deploy](https://www.cargo-lambda.info/commands/deploy.html) 子命令將編譯後的二進位檔部署至 Lambda。此命令會建立[執行角色](lambda-intro-execution-role.md)，然後建立 Lambda 函數。若要指定現有的執行角色，請使用 [--iam-role 標記](https://www.cargo-lambda.info/commands/deploy.html#iam-roles)。

```
cargo lambda deploy my-function
```

### 使用 部署 Rust 函數二進位檔 AWS CLI
<a name="rust-deploy-aws-cli"></a>

您也可以使用 部署二進位檔 AWS CLI。

1. 使用 [build](https://www.cargo-lambda.info/commands/build.html) 子命令，建置 .zip 部署套件。

   ```
   cargo lambda build --release --output-format zip
   ```

1. 若要部署 .zip 套件至 Lambda，請執行 [create-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) 命令。
   + 對於 `--runtime`，請指定 `provided.al2023`。這是[僅限作業系統的執行時期](runtimes-provided.md)。僅限作業系統的執行時期用於將編譯的二進位檔和自訂執行時期部署至 Lambda。
   + 針對 `--role`，指定[執行角色](lambda-intro-execution-role.md)的 ARN。

   ```
   aws lambda create-function \
        --function-name my-function \
        --runtime provided.al2023 \
        --role arn:aws:iam::111122223333:role/lambda-role \
        --handler rust.handler \
        --zip-file fileb://target/lambda/my-function/bootstrap.zip
   ```

### 使用 CLI 部署 Rust AWS SAM 函數二進位檔
<a name="rust-deploy-sam-cli"></a>

您也可以使用 AWS SAM CLI 部署二進位檔。

1. 使用資源和屬性定義建立 AWS SAM 範本。對於 `Runtime`，請指定 `provided.al2023`。這是[僅限作業系統的執行時期](runtimes-provided.md)。僅限作業系統的執行時期用於將編譯的二進位檔和自訂執行時期部署至 Lambda。

   如需使用 部署 Lambda 函數的詳細資訊 AWS SAM，請參閱《 *AWS Serverless Application Model 開發人員指南*》中的 [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)。  
**Example Rust 二進位檔的 SAM 資源和屬性定義**  

   ```
   AWSTemplateFormatVersion: '2010-09-09'
   Transform: AWS::Serverless-2016-10-31
   Description: SAM template for Rust binaries
   Resources:
     RustFunction:
       Type: AWS::Serverless::Function 
       Properties:
         CodeUri: target/lambda/my-function/
         Handler: rust.handler
         Runtime: provided.al2023
   Outputs:
     RustFunction:
       Description: "Lambda Function ARN"
       Value: !GetAtt RustFunction.Arn
   ```

1. 使用 [build](https://www.cargo-lambda.info/commands/build.html) 子命令來編譯函數。

   ```
   cargo lambda build --release
   ```

1. 使用 [sam deploy](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html) 命令將函數部署到 Lambda。

   ```
   sam deploy --guided
   ```

如需使用 CLI 建置 Rust AWS SAM 函數的詳細資訊，請參閱《 *AWS Serverless Application Model 開發人員指南*[》中的使用 Cargo Lambda 建置 Rust Lambda 函數](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/building-rust.html)。

## 使用 Cargo Lambda 叫用您的 Rust 函數
<a name="rust-invoke-function"></a>

使用 [invoke](https://www.cargo-lambda.info/commands/invoke.html) 子命令，透過承載來測試您的函數。

```
cargo lambda invoke --remote --data-ascii '{"command": "Hello world"}' my-function
```

### 使用 叫用 Rust 函數 AWS CLI
<a name="rust-invoke-cli"></a>

您也可以使用 AWS CLI 來叫用 函數。

```
aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"command": "Hello world"}' /tmp/out.txt
```

如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

# 使用 Rust Lambda 函式的層
<a name="rust-layers"></a>

不建議使用[層](chapter-layers.md)來管理以 Rust 編寫的 Lambda 函式相依項。這是因為以 Rust 編寫的 Lambda 函式會編譯為單一可執行檔，並在部署函式時提供給 Lambda。此可執行檔包含經過編譯的函數程式碼及其所有相依項。使用層不僅會使程序複雜化，還會導致冷啟動時間增加，因為函數需要在初始化階段期間將額外的組件載入記憶體。

若要在 Rust 處理常式中使用外部相依項，請直接將其納入部署套件。如此一來，您既能簡化部署程序，又能利用內建的 Rust 編譯器最佳化。如需如何在函式中匯入與使用適用於 Rust 的 AWS SDK 等相依項的範例，請參閱[在 Rust 中定義 Lambda 函式處理常式](rust-handler.md)。

# 記錄和監控 Rust Lambda 函數
<a name="rust-logging"></a>

AWS Lambda 會自動代表您監控 Lambda 函數，並將日誌傳送至 Amazon CloudWatch。您的 Lambda 函數隨附有 CloudWatch Logs 日誌群組，且函數的每一執行個體各有一個日誌串流。Lambda 執行期環境會將每次調用的詳細資訊傳送至日誌串流，並且轉傳來自函數程式碼的日誌及其他輸出。如需詳細資訊，請參閱[將 Lambda 函式日誌傳送至 CloudWatch Logs](monitoring-cloudwatchlogs.md)。如需設定日誌格式的資訊，請參閱 [設定 JSON 和純文字日誌格式](monitoring-cloudwatchlogs-logformat.md)。此頁面說明如何從 Lambda 函數的程式碼中產生日誌輸出。

## 建立編寫日誌的函數
<a name="rust-logging-function"></a>

若要從您的函式程式碼輸出日誌，可使用寫入到 `stdout` 或 `stderr` 的任何日誌記錄函數，例如 `println!` 巨集。下列範例使用 `println!` 在函數處理常式啟動時和完成之前列印訊息。

```
use lambda_runtime::{service_fn, LambdaEvent, Error};
use serde_json::{json, Value};
async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    println!("Rust function invoked");
    let payload = event.payload;
    let first_name = payload["firstName"].as_str().unwrap_or("world");
    println!("Rust function responds to {}", &first_name);
    Ok(json!({ "message": format!("Hello, {first_name}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}
```

## 實作帶有追蹤套件的進階日誌記錄
<a name="rust-logging-tracing"></a>

[追蹤](https://crates.io/crates/tracing)是檢測 Rust 程式以收集結構化、以事件為基礎的診斷資訊的架構。此架構提供公用程式來自訂日誌記錄輸出層級和格式，例如建立結構化的 JSON 日誌訊息。若要使用此架構，必須在實作函數處理常式之前初始化 `subscriber`。然後，您可以使用追蹤巨集 (例如 `debug`、`info` 和 `error`) 來指定每個案例所需的日誌記錄層級。

**Example – 使用追蹤套件**  
注意下列事項：  
+ `tracing_subscriber::fmt().json()`：包含此選項時，日誌會格式化為 JSON。若要使用此選項，必須將 `json` 功能包含在 `tracing-subscriber` 相依項中 (例如，`tracing-subscriber = { version = "0.3.11", features = ["json"] }`)。
+ `#[tracing::instrument(skip(event), fields(req_id = %event.context.request_id))]`：每次叫用處理常式時，此註釋都會產生一個範圍。此範圍會將請求 ID 新增至每個日誌行。
+ `{ %first_name }`：此建構模組將 `first_name` 欄位新增到使用該欄位的日誌行。此欄位的值對應具有相同名稱的變數。

```
use lambda_runtime::{service_fn, Error, LambdaEvent};
use serde_json::{json, Value};
#[tracing::instrument(skip(event), fields(req_id = %event.context.request_id))]
async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    tracing::info!("Rust function invoked");
    let payload = event.payload;
    let first_name = payload["firstName"].as_str().unwrap_or("world");
    tracing::info!({ %first_name }, "Rust function responds to event");
    Ok(json!({ "message": format!("Hello, {first_name}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt().json()
        .with_max_level(tracing::Level::INFO)
        // this needs to be set to remove duplicated information in the log.
        .with_current_span(false)
        // this needs to be set to false, otherwise ANSI color codes will
        // show up in a confusing manner in CloudWatch logs.
        .with_ansi(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        // remove the name of the function from every log entry
        .with_target(false)
        .init();
    lambda_runtime::run(service_fn(handler)).await
}
```

叫用此 Rust 函數時，其會列印類似於以下內容的兩條日誌行：

```
{"level":"INFO","fields":{"message":"Rust function invoked"},"spans":[{"req_id":"45daaaa7-1a72-470c-9a62-e79860044bb5","name":"handler"}]}
{"level":"INFO","fields":{"message":"Rust function responds to event","first_name":"David"},"spans":[{"req_id":"45daaaa7-1a72-470c-9a62-e79860044bb5","name":"handler"}]}
```