

# 创建和管理 Lambda 函数 URL
<a name="urls-configuration"></a>

函数 URL 是 Lambda 函数的专用 HTTP(S) 端点。您可以通过 Lambda 控制台或 Lambda API 创建和配置函数 URL。

**提示**  
Lambda 提供了两种方法来通过 HTTP 端点调用函数：函数 URL 和 Amazon API Gateway。如果您不确定哪种方法最适合您的应用场景，请参阅[选择使用 HTTP 请求调用 Lambda 函数的方法](furls-http-invoke-decision.md)。

创建函数 URL 时，Lambda 会自动为您生成唯一的 URL 端点。创建函数 URL 后，其 URL 端点永远不会改变。函数 URL 的端点具有以下格式：

```
https://<url-id>.lambda-url.<region>.on.aws
```

**注意**  
以下 AWS 区域不支持函数 URL：亚太地区（海得拉巴）(`ap-south-2`)、亚太地区（墨尔本）(`ap-southeast-4`)、亚太地区（马来西亚）(`ap-southeast-5`)、亚太地区（新西兰）(`ap-southeast-6`)、亚太地区（泰国）(`ap-southeast-7`)、亚太地区（台北）(`ap-east-2`)、加拿大西部（卡尔加里）(`ca-west-1`)、欧洲（西班牙）(`eu-south-2`)、欧洲（苏黎世）(`eu-central-2`)、以色列（特拉维夫）(`il-central-1`) 和中东（阿联酋）(`me-central-1`)。

函数 URL 启用了双堆栈，支持 IPv4 和 IPv6。为函数配置函数 URL 后，可以通过 Web 浏览器、curl、Postman 或任何 HTTP 客户端通过其 HTTP（S）端点调用函数。

**注意**  
您只能通过公共 Internet 访问自己的函数 URL。虽然 Lambda 函数确实支持 AWS PrivateLink，但函数 URL 并不支持。

Lambda 函数 URL 使用[基于资源的策略](access-control-resource-based.md)进行安全和访问控制。函数 URL 还支持跨源资源共享 (CORS) 配置选项。

可以将函数 URL 应用于任何函数别名或 `$LATEST` 未发布的函数版本。不能将函数 URL 添加到任何其他函数版本。

以下部分介绍如何使用 Lambda 控制台、AWS CLI 和 CloudFormation 模板创建和管理函数 URL

**Topics**
+ [创建函数 URL（控制台）](#create-url-console)
+ [创建函数 URL (AWS CLI)](#create-url-cli)
+ [向 CloudFormation 模板添加函数 URL](#urls-cfn)
+ [跨源资源共享 (CORS)](#urls-cors)
+ [节流函数 URL](#urls-throttling)
+ [停用函数 URL](#urls-deactivating)
+ [删除函数 URL](#w2aac39c81c53)
+ [控制对 Lambda 函数 URL 的访问](urls-auth.md)
+ [调用 Lambda 函数 URL](urls-invocation.md)
+ [监控 Lambda 函数 URL](urls-monitoring.md)
+ [选择使用 HTTP 请求调用 Lambda 函数的方法](furls-http-invoke-decision.md)
+ [教程：使用 Lambda 函数 URL 创建 Webhooook 端点](urls-webhook-tutorial.md)

## 创建函数 URL（控制台）
<a name="create-url-console"></a>

按照以下步骤，使用控制台创建函数 URL。

### 为现有函数创建函数 URL
<a name="create-url-existing-function"></a>

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择您要为其创建函数 URL 的函数的名称。

1. 选择 **Configuration**（配置）选项卡，然后选择 **Function URL**（函数 URL）。

1. 选择 **Create function URL**（创建函数 URL）。

1. 对于 **Auth type**（身份验证类型），选择 **AWS\$1IAM** 或 **NONE**。有关函数 URL 身份验证的更多信息，请参阅 [访问控制](urls-auth.md)。

1. （可选）选择 **Configure cross-origin resource sharing (CORS)**（配置跨源资源共享），然后为函数 URL 配置 CORS 设置。有关 CORS 的更多信息，请参阅 [跨源资源共享 (CORS)](#urls-cors)。

1. 选择**保存**。

这将为函数的 `$LATEST` 未发布版本创建函数 URL。函数 URL 将显示在控制台的 **Function overview**（函数概览）部分。

### 为现有别名创建函数 URL
<a name="create-url-existing-alias"></a>

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择具有您要为其创建函数 URL 的别名的函数的名称。

1. 选择 **Aliases**（别名）选项卡，然后选择要为其创建函数 URL 的别名的名称。

1. 选择 **Configuration**（配置）选项卡，然后选择 **Function URL**（函数 URL）。

1. 选择 **Create function URL**（创建函数 URL）。

1. 对于 **Auth type**（身份验证类型），选择 **AWS\$1IAM** 或 **NONE**。有关函数 URL 身份验证的更多信息，请参阅 [访问控制](urls-auth.md)。

1. （可选）选择 **Configure cross-origin resource sharing (CORS)**（配置跨源资源共享），然后为函数 URL 配置 CORS 设置。有关 CORS 的更多信息，请参阅 [跨源资源共享 (CORS)](#urls-cors)。

1. 选择**保存**。

这将为函数别名创建函数 URL。函数 URL 将显示在控制台中您的别名的 **Function overview**（函数概览）部分。

### 创建具有函数 URL 的新函数
<a name="create-url-new-function"></a>

**创建具有函数 URL 的新函数（控制台）**

1. 打开 Lamba 控制台的 [Functions page](https://console.aws.amazon.com/lambda/home#/functions)（函数页面）。

1. 选择 **Create function**（创建函数）。

1. 在**基本信息**中，执行以下操作：

   1. 在 **Function name**（函数名称）中，输入您的函数的名称，例如 **my-function**。

   1. 对于**运行时**，请选择您首选的语言运行时，例如 **Node.js 24**。

   1. 对于 **Architecture**（架构），请选择 **x86\$164** 或 **arm64**。

   1. 展开 **Permissions**（权限），然后选择是创建新的执行角色还是使用现有的执行角色。

1. 展开 **Advanced settings**（高级设置），然后选择 **Function URL**（函数 URL）。

1. 对于 **Auth type**（身份验证类型），选择 **AWS\$1IAM** 或 **NONE**（无）。有关函数 URL 身份验证的更多信息，请参阅 [访问控制](urls-auth.md)。

1. （可选）选择 **Configure cross-origin resource sharing (CORS)**（配置跨源资源共享）。如果在函数创建过程中选择此选项，则原定设置下，函数 URL 将允许来自所有来源的请求。创建函数后，可以编辑函数 URL 的 CORS 设置。有关 CORS 的更多信息，请参阅 [跨源资源共享 (CORS)](#urls-cors)。

1. 选择**创建函数**。

这将为函数的 `$LATEST` 未发布版本创建一个具有函数 URL 的新函数。函数 URL 将显示在控制台的 **Function overview**（函数概览）部分。

## 创建函数 URL (AWS CLI)
<a name="create-url-cli"></a>

要使用 AWS Command Line Interface (AWS CLI) 为现有 Lambda 函数创建函数 URL，请运行以下命令：

```
aws lambda create-function-url-config \
    --function-name my-function \
    --qualifier prod \ // optional
    --auth-type AWS_IAM
    --cors-config {AllowOrigins="https://example.com"} // optional
```

这会将函数 URL 添加到函数 **my-function** 的 **prod** 限定符中。有关这些配置参数的更多信息，请参阅 API 参考中的[CreateFunctionUrlConfig](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunctionUrlConfig.html)。

**注意**  
要通过 AWS CLI 创建函数 URL，该函数必须已经存在。

## 向 CloudFormation 模板添加函数 URL
<a name="urls-cfn"></a>

要向 CloudFormation 模板中添加 `AWS::Lambda::Url` 资源，请使用以下语法：

### JSON
<a name="urls-cfn-json"></a>

```
{
  "Type" : "AWS::Lambda::Url",
  "Properties" : {
      "AuthType" : String,
      "Cors" : Cors,
      "Qualifier" : String,
      "TargetFunctionArn" : String
    }
}
```

### YAML
<a name="urls-cfn-yaml"></a>

```
Type: AWS::Lambda::Url
Properties: 
  AuthType: String
  Cors: 
    Cors
  Qualifier: String
  TargetFunctionArn: String
```

### 参数
<a name="urls-cfn-params"></a>
+ （必需）`AuthType` – 定义函数 URL 的身份验证类型。可能的值为 `AWS_IAM` 或 `NONE`。若要将访问权限限制为仅经过身份验证的用户，请设置为 `AWS_IAM`。要绕过 IAM 身份验证并允许任何用户对您的函数发出请求，请设置为 `NONE`。
+ （可选）`Cors` – 定义函数 URL 的 [CORS settings](#urls-cors)（CORS 设置）。要在 CloudFormation 中向 `AWS::Lambda::Url` 资源添加 `Cors`，请使用以下语法。

    
**Example AWS::Lambda::Url.Cors (JSON)**  

  ```
  {
    "AllowCredentials" : Boolean,
    "AllowHeaders" : [ String, ... ],
    "AllowMethods" : [ String, ... ],
    "AllowOrigins" : [ String, ... ],
    "ExposeHeaders" : [ String, ... ],
    "MaxAge" : Integer
  }
  ```  
**Example AWS::Lambda::Url.Cors (YAML)**  

  ```
    AllowCredentials: Boolean
    AllowHeaders: 
      - String
    AllowMethods: 
      - String
    AllowOrigins: 
      - String
    ExposeHeaders: 
      - String
    MaxAge: Integer
  ```
+ （可选）`Qualifier` – 别名。
+ （必需）`TargetFunctionArn` – Lambda 函数的名称或 Amazon 资源名称（ARN）。有效的名称格式包括：
  + **函数名称** – `my-function`
  + **函数 ARN** – `arn:aws:lambda:us-west-2:123456789012:function:my-function`
  + **部分 ARN** – `123456789012:function:my-function`

## 跨源资源共享 (CORS)
<a name="urls-cors"></a>

要定义不同来源如何访问函数 URL，请使用 [跨源资源共享 (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)。如果要从其他域调用函数 URL，建议配置 CORS。Lambda 支持函数 URL 的以下 CORS 标头。


| CORS 标头 | CORS 配置属性 | 示例值 | 
| --- | --- | --- | 
|  [ Access-Control-Allow-Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)  |  `AllowOrigins`  |  `*`（允许所有源） `https://www.example.com` `http://localhost:60905`  | 
|  [ Access-Control-Allow-Methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods)  |  `AllowMethods`  |  `GET`, `POST`, `DELETE`, `*`  | 
|  [ Access-Control-Allow-Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers)  |  `AllowHeaders`  |  `Date`, `Keep-Alive`, `X-Custom-Header`  | 
|  [ Access-Control-Expose-Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)  |  `ExposeHeaders`  |  `Date`, `Keep-Alive`, `X-Custom-Header`  | 
|  [ Access-Control-Allow-Credentials](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials)  |  `AllowCredentials`  |  `TRUE`  | 
|  [ Access-Control-Max-Age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age)  |  `MaxAge`  |  `5` (默认值)`300`  | 

使用 Lambda 控制台或 AWS CLI 为函数 URL 配置 CORS 时，Lambda 会通过函数 URL 自动将 CORS 标头添加到所有响应中。或者，您也可以手动将 CORS 标头添加到函数响应中。如果存在冲突的标头，则预期行为取决于请求的类型：
+ 对于 OPTIONS 请求之类的预检请求，以函数 URL 上配置的 CORS 标头为准。Lambda 在响应中仅返回这些 CORS 标头。
+ 对于 GET 或 POST 请求之类的非预检请求，Lambda 会同时返回函数 URL 上配置的 CORS 标头以及函数返回的 CORS 标头。这可能会导致响应中出现重复的 CORS 标头。您将看到类似以下的错误：`The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed`。

通常，我们建议在函数 URL 上配置所有 CORS 设置，而不是在函数响应中手动发送 CORS 标头。

## 节流函数 URL
<a name="urls-throttling"></a>

节流限制了函数处理请求的速率。这在很多情况下都很有用，比如防止函数过载下游资源，或者处理请求突然激增的情况。

通过配置预留并发，可以节流 Lambda 函数通过函数 URL 处理请求的速率。预留并发限制了函数的最大并发调用次数。函数的最大每秒请求速率 (RPS) 相当于配置的预留并发的 10 倍。例如，如果将函数配置为预留并发 100，则最大 RPS 为 1,000。

当函数并发超过预留并发时，函数 URL 将返回 HTTP `429` 状态码。如果您的函数收到的请求超过了基于您配置的预留并发的最大 10 倍 RPS，那么您也会收到一个 HTTP `429` 错误。有关预留并发的更多信息，请参阅 [为函数配置预留并发](configuration-concurrency.md)。

## 停用函数 URL
<a name="urls-deactivating"></a>

在紧急情况下，您可能希望拒绝函数 URL 的所有流量。要停用函数 URL，请将预留并发设置为零。这会节流对函数 URL 的所有请求，从而产生 HTTP `429` 状态响应。要重新激活函数 URL，请删除预留的并发配置，或将配置设置为大于零的数量。

## 删除函数 URL
<a name="w2aac39c81c53"></a>

删除函数 URL 后，将无法恢复。创建一个新函数 URL 将导致不同的 URL 地址。

**注意**  
如果您删除身份验证类型为 `NONE` 的函数 URL，Lambda 不会自动删除关联的基于资源的策略。如果要删除此策略，您必须手动执行该操作。

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择此函数的名称。

1. 选择 **Configuration**（配置）选项卡，然后选择 **Function URL**（函数 URL）。

1. 选择**删除**。

1. 在此字段中输入 *delete*（删除）短语以确认删除。

1. 选择**删除**。

**注意**  
删除具有函数 URL 的函数后，Lambda 会异步删除函数 URL。如果您立即在同一个账户中创建具有相同名称的新函数，则原始函数 URL 可能会被映射到新函数，而不是被删除。

# 控制对 Lambda 函数 URL 的访问
<a name="urls-auth"></a>

**注意**  
从 2025 年 10 月开始，新的函数 URL 将同时需要 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限。

您可以使用 [AuthType](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunctionUrlConfig.html#lambda-CreateFunctionUrlConfig-request-AuthType) 参数和附上特定函数的[基于资源的策略](access-control-resource-based.md)来控制对 Lambda 函数 URL 的访问。这两个组件的配置决定了谁可以对函数 URL 调用或执行其他管理操作。

`AuthType` 参数确定了 Lambda 如何对函数 URL 的请求进行身份验证或授权。配置函数 URL 时，必须指定以下 `AuthType` 选项之一：
+ `AWS_IAM` – Lambda 根据 IAM 主体的身份策略和函数基于资源的策略使用 AWS Identity and Access Management (IAM) 对请求进行身份验证和授权。如果只希望经过身份验证的用户和角色使用函数 URL 调用函数，请选择此选项。
+ `NONE` – Lambda 在调用函数之前不会执行任何身份验证。但是，函数基于资源的策略始终有效，并且必须在函数 URL 接收请求之前授予公有访问权限。选择此选项可允许对函数 URL 进行未经身份验证的公有访问。

要了解更多关于安全性的洞察，可以使用 AWS Identity and Access Management Access Analyzer 获取对函数 URL 的外部访问的全面分析。IAM Access Analyzer 还可以监控 Lambda 函数的新权限或更新权限，以帮助您识别授予公有和跨账户访问的权限。可免费使用 IAM Access Analyzer。要开始使用 IAM Access Analyzer，请参阅[使用 AWS IAM Access Analyzer](https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html)。

该页面包含两种身份验证类型的基于资源的策略示例，以及如何使用 [AddPermission](https://docs.aws.amazon.com/lambda/latest/api/API_AddPermission.html) API 操作或 Lambda 控制台创建这些策略。有关设置权限后如何调用函数 URL 的信息，请参阅[调用 Lambda 函数 URL](urls-invocation.md)。

**Topics**
+ [使用 `AWS_IAM` 身份验证类型](#urls-auth-iam)
+ [使用 `NONE` 身份验证类型](#urls-auth-none)
+ [治理和访问控制](#urls-governance)

## 使用 `AWS_IAM` 身份验证类型
<a name="urls-auth-iam"></a>

如果选择 `AWS_IAM` 身份验证类型，则需要调用 Lambda 函数 URL 的用户必须具有 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限。根据发出调用请求的人员，您可能需要使用[基于资源的策略](access-control-resource-based.md)授予此权限。

如果发出请求的主体与函数 URL 的 AWS 账户 相同，则主体必须****在其[基于身份的策略](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html)中拥有 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限，**或者**在函数基于资源的策略中获授权限。换句话说，如果用户已经在其基于身份的策略中拥有 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限，则基于资源的策略为可选。策略评估遵循[策略评估逻辑](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html)中概述的规则。

如果发出请求的主体位于不同的账户中，则主体必须**同时**具有基于身份的策略（该策略为其提供 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限）**和**基于资源的策略（基于其尝试调用的函数）中授予的权限。策略评估遵循[确定是否允许跨账户请求](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic-cross-account.html#policy-eval-cross-account)中概述的规则。

以下基于资源的策略允许 AWS 账户 `444455556666` 中的 `example` 角色调用与函数 `my-function` 关联的函数 URL：[lambda:InvokedViaFunctionUrl](https://docs.aws.amazon.com/lambda/latest/api/API_AddPermission.html#lambda-AddPermission-request-InvokedViaFunctionUrl) 上下文键将操作 `lambda:InvokeFunction` 限制为函数 URL 的调用。这意味着主体必须使用函数 URL 来调用该函数。如果不包含 `lambda:InvokedViaFunctionUrl`，则除了函数 URL 之外，主体还可以通过其他调用方法调用函数。

**Example — 基于跨账户资源的策略**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::444455556666:role/example"
      },
      "Action": "lambda:InvokeFunctionUrl",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:my-function",
      "Condition": {
        "StringEquals": {
          "lambda:FunctionUrlAuthType": "AWS_IAM"
        }
      }
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::444455556666:role/example"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:my-function",
      "Condition": {
        "Bool": {
          "lambda:InvokedViaFunctionUrl": "true"
        }
      }
    }
  ]
}
```

您可以按照以下步骤通过控制台创建这一基于资源的策略：

**将 URL 调用权限授予另一个账户（控制台）**

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择要为其授予 URL 调用权限的函数的名称。

1. 选择 **Configuration**（配置）选项卡，然后选择 **Permissions**（权限）。

1. 在 **Resource-based policy**（基于资源的策略）下，选择 **Add permissions**（添加权限）。

1. 选择 **Function URL**（函数 URL）。

1. 对于 **Auth type**（身份验证类型），选择 **AWS\$1IAM**。

1. 输入策略语句的**语句 ID**。

1. 对于**主体**，请输入要向其授予权限的用户或角色的 Amazon 资源名称（ARN）。例如：**444455556666**。

1. 选择**保存**。

或者，也可以使用以下 [add-permission](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/add-permission.html) AWS Command Line Interface (AWS CLI) 命令创建此策略：使用 AWS CLI 时，必须单独添加 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 语句。例如：

```
aws lambda add-permission --function-name my-function \
  --statement-id UrlPolicyInvokeURL \
  --action lambda:InvokeFunctionUrl \
  --principal 444455556666 \
  --function-url-auth-type AWS_IAM
```

```
aws lambda add-permission --function-name my-function \
  --statement-id UrlPolicyInvokeFunction \
  --action lambda:InvokeFunction \
  --principal 444455556666 \
  --invoked-via-function-url
```

## 使用 `NONE` 身份验证类型
<a name="urls-auth-none"></a>

**重要**  
当您的函数 URL 身份验证类型为 `NONE` 且您有[基于资源的策略](access-control-resource-based.md)授予公有访问权限时，任何使用您函数 URL 的未经身份验证的用户都可以调用您的函数。

在某些情况下，您可能希望函数 URL 为公有。例如，您可能希望处理直接从 Web 浏览器发出的请求。要允许函数 URL 公有访问权限，请选择 `NONE` 身份验证类型。

如果选择 `NONE` 身份验证类型，Lambda 不会使用 IAM 对函数 URL 的请求进行身份验证。但是，函数必须拥有允许 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 的基于资源的策略。使用控制台或 AWS Serverless Application Model (AWS SAM) 创建具有身份验证类型 `NONE` 的函数 URL 时，Lambda 会自动创建基于资源的策略。如果直接使用 AWS CLI、AWS CloudFormation 或 Lambda API，则必须[自己添加策略](#policy-cli)。

我们建议在使用 `NONE` 身份验证类型时，在基于资源的策略中包含 [lambda:InvokedViaFunctionUrl](https://docs.aws.amazon.com/lambda/latest/api/API_AddPermission.html#lambda-AddPermission-request-InvokedViaFunctionUrl) 上下文键。此上下文键可确保只能通过函数 URL 调用函数，而不能通过其他调用方法进行调用。

请注意有关该策略的以下信息：
+ 所有实体均可调用 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction`。这意味着拥有函数 URL 的任何人都可以调用函数。
+ `lambda:FunctionUrlAuthType` 条件键值为 `NONE`。这意味着，此策略仅在函数 URL 的身份验证类型也为 `NONE` 时允许访问。
+ 该 `lambda:InvokedViaFunctionUrl` 条件可确保只能通过函数 URL 调用该函数，而不能通过其他调用方法进行调用。

**Example — NONE 身份验证类型默认基于资源的策略**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "FunctionURLAllowPublicAccess",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "lambda:InvokeFunctionUrl",
      "Resource": "arn:aws:lambda:us-east-2:123456789012:function:my-function",
      "Condition": {
        "StringEquals": {
          "lambda:FunctionUrlAuthType": "NONE"
        }
      }
    },
    {
      "Sid": "FunctionURLInvokeAllowPublicAccess",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-2:123456789012:function:my-function",
      "Condition": {
        "Bool": {
          "lambda:InvokedViaFunctionUrl": "true"
        }
      }
    }
  ]
}
```

**使用 AWS CLI 创建基于资源的策略**  
除非使用控制台或 AWS SAM 创建身份验证类型为 `NONE` 的函数 URL，否则必须自己添加基于资源的策略。使用以下命令，创建 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限的语句。每条语句都必须添加到单独的命令中。

```
aws lambda add-permission \
  --function-name UrlTestFunction \
  --statement-id UrlPolicyInvokeURL \
  --action lambda:InvokeFunctionUrl \
  --principal * \
  --function-url-auth-type NONE
```

```
aws lambda add-permission \
  --function-name UrlTestFunction \
  --statement-id UrlPolicyInvokeFunction \
  --action lambda:InvokeFunction \
  --principal * \
  --invoked-via-function-url
```

**注意**  
如果您删除身份验证类型为 `NONE` 的函数 URL，Lambda 不会自动删除关联的基于资源的策略。如果要删除此策略，您必须手动执行该操作。

如果函数基于资源的策略未授予 `lambda:invokeFunctionUrl` 和 `lambda:InvokeFunction` 权限，则用户在尝试调用函数 URL 时，将收到 403 禁止的错误代码。即使函数 URL 使用 `NONE` 身份验证类型，也会发生这种情况。

## 治理和访问控制
<a name="urls-governance"></a>

除了函数 URL 调用权限外，还可以控制对用于配置函数 URL 的操作的访问。Lambda 支持以下针对函数 URL 的 IAM policy 操作：
+ `lambda:InvokeFunctionUrl` – 使用函数 URL 调用 Lambda 函数。
+ `lambda:CreateFunctionUrlConfig` – 创建函数 URL 并设置其 `AuthType`。
+ `lambda:UpdateFunctionUrlConfig` – 更新函数 URL 配置及其 `AuthType`。
+ `lambda:GetFunctionUrlConfig` – 查看函数 URL 的详细信息。
+ `lambda:ListFunctionUrlConfigs` – 列出函数 URL 配置。
+ `lambda:DeleteFunctionUrlConfig` – 删除函数 URL。

要允许或拒绝对其他 AWS 实体的函数 URL 访问，请在 IAM policy 中包含这些操作。例如，以下策略授予 AWS 账户 `444455556666` 中的 `example` 角色在账户 `123456789012` 中更新函数 **my-function** 的函数 URL 的权限。

**Example 跨账户函数 URL 策略**    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": { 
                "AWS": "arn:aws:iam::444455556666:role/example"
            },
            "Action": "lambda:UpdateFunctionUrlConfig",
            "Resource": "arn:aws:lambda:us-east-2:123456789012:function:my-function"
        }
    ]
}
```

### 条件键
<a name="urls-condition-keys"></a>

要对函数 URL 进行精细访问控制，请使用条件上下文键。Lambda 支持函数 URL 的以下上下文键：
+ `lambda:FunctionUrlAuthType` – 定义了一个枚举值，描述函数 URL 使用的身份验证类型。该值可以是 `AWS_IAM` 或 `NONE`。
+ `lambda:InvokedViaFunctionUrl` — 将 `lambda:InvokeFunction` 操作限制为通过函数 URL 进行调用。这可以确保只能使用函数 URL 调用该函数，而不能通过其他调用方法进行调用。有关使用 `lambda:InvokedViaFunctionUrl` 上下文键的基于资源的策略示例，请参阅[使用 `AWS_IAM` 身份验证类型](#urls-auth-iam)和[使用 `NONE` 身份验证类型](#urls-auth-none)中的示例。

可以在与函数关联的策略中使用这些上下文键。例如，您可能希望限制谁可以对函数 URL 进行配置更改。要拒绝对 URL 身份验证类型 `NONE` 的任何函数的所有 `UpdateFunctionUrlConfig` 请求，可以定义以下策略：

**Example 带有显式拒绝的函数 URL 策略**    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action":[
                "lambda:UpdateFunctionUrlConfig"
            ],
            "Resource": "arn:aws:lambda:us-east-1:123456789012:function:*",
            "Condition": {
                "StringEquals": {
                    "lambda:FunctionUrlAuthType": "NONE"
                }
            }
        }
    ]
}
```

要授予 AWS 账户 `444455556666` 中的 `example` 角色对 URL 身份验证类型 `AWS_IAM` 的函数进行 `CreateFunctionUrlConfig` 和 `UpdateFunctionUrlConfig` 请求的权限，可以定义以下策略：

**Example 带有显式允许的函数 URL 策略**    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": { 
                "AWS": "arn:aws:iam::444455556666:role/example"
            },
            "Action":[
                "lambda:CreateFunctionUrlConfig",
                "lambda:UpdateFunctionUrlConfig"
            ],
            "Resource": "arn:aws:lambda:us-east-1:123456789012:function:*",
            "Condition": {
                "StringEquals": {
                    "lambda:FunctionUrlAuthType": "AWS_IAM"
                }
            }
        }
    ]
}
```

您还可以在[服务控制策略](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html)（SCP）中使用此条件键。使用 SCP 在 AWS Organizations 中管理整个企业的权限。例如，要拒绝用户创建或更新使用除 `AWS_IAM` 身份验证类型以外的任何身份验证类型的函数 URL，请使用以下服务控制策略：

**Example 带有显式拒绝的函数 URL SCP**    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Deny",
            "Action":[
                "lambda:CreateFunctionUrlConfig",
                "lambda:UpdateFunctionUrlConfig"
            ],
            "Resource": "arn:aws:lambda:*:123456789012:function:*",
            "Condition": {
                "StringNotEquals": {
                    "lambda:FunctionUrlAuthType": "AWS_IAM"
                }
            }
        }
    ]
}
```

# 调用 Lambda 函数 URL
<a name="urls-invocation"></a>

函数 URL 是 Lambda 函数的专用 HTTP(S) 端点。您可以通过 Lambda 控制台或 Lambda API 创建和配置函数 URL。

**提示**  
Lambda 提供了两种方法来通过 HTTP 端点调用函数：函数 URL 和 Amazon API Gateway。如果您不确定哪种方法最适合您的应用场景，请参阅[选择使用 HTTP 请求调用 Lambda 函数的方法](furls-http-invoke-decision.md)。

创建函数 URL 时，Lambda 会自动为您生成唯一的 URL 端点。创建函数 URL 后，其 URL 端点永远不会改变。函数 URL 的端点具有以下格式：

```
https://<url-id>.lambda-url.<region>.on.aws
```

**注意**  
以下 AWS 区域不支持函数 URL：亚太地区（海得拉巴）(`ap-south-2`)、亚太地区（墨尔本）(`ap-southeast-4`)、亚太地区（马来西亚）(`ap-southeast-5`)、亚太地区（新西兰）(`ap-southeast-6`)、亚太地区（泰国）(`ap-southeast-7`)、亚太地区（台北）(`ap-east-2`)、加拿大西部（卡尔加里）(`ca-west-1`)、欧洲（西班牙）(`eu-south-2`)、欧洲（苏黎世）(`eu-central-2`)、以色列（特拉维夫）(`il-central-1`) 和中东（阿联酋）(`me-central-1`)。

函数 URL 启用了双堆栈，支持 IPv4 和 IPv6。配置函数 URL 后，可以通过 Web 浏览器、curl、Postman 或任何 HTTP 客户端通过其 HTTP(S) 端点调用函数。要调用函数 URL，您必须具有 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限。有关更多信息，请参阅[访问控制](urls-auth.md)。

**Topics**
+ [函数 URL 调用基础](#urls-invocation-basics)
+ [请求和响应有效负载](#urls-payloads)

## 函数 URL 调用基础
<a name="urls-invocation-basics"></a>

如果函数 URL 使用 `AWS_IAM` 身份验证类型，则必须使用 [AWS 签名版本 4 (SigV4)](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) 对每个 HTTP 请求进行签名。[Postman](https://quickstarts.postman.com/guide/aws/index.html?index=..%2F..index#2) 等工具提供了内置的方法使用 SigV4 对请求进行签名。

如果不使用工具向函数 URL 对 HTTP 请求进行签名，则必须使用 SigV4 手动对每个请求进行签名。当函数 URL 收到请求时，Lambda 还会计算 SigV4 签名。Lambda 仅在签名匹配时处理请求。有关如何使用 SigV4 手动对请求进行签名的说明，请参阅*《Amazon Web Services 一般参考 指南》*中的[利用签名版本 4 对 AWS 请求进行签名](https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html)。

如果函数 URL 使用 `NONE` 身份验证类型，则不必使用 SigV4 对请求进行签名。您可以使用 Web 浏览器、curl、Postman 或任何 HTTP 客户端来调用函数。

要测试对函数的简单 `GET` 请求，请使用 Web 浏览器。例如，如果您的函数 URL 为 `https://abcdefg.lambda-url.us-east-1.on.aws`，并且包含一个字符串参数 `message`，那么您的请求 URL 可能如下所示：

```
https://abcdefg.lambda-url.us-east-1.on.aws/?message=HelloWorld
```

要测试其他 HTTP 请求，例如 `POST` 请求，可以使用 curl 之类的工具。例如，如果希望在对函数 URL 的 `POST` 请求中包含一些 JSON 数据，可以使用以下 curl 命令：

```
curl -v 'https://abcdefg.lambda-url.us-east-1.on.aws/?message=HelloWorld' \
-H 'content-type: application/json' \
-d '{ "example": "test" }'
```

## 请求和响应有效负载
<a name="urls-payloads"></a>

当客户端调用函数 URL 时，Lambda 会将请求映射到事件对象，然后再将其传递给函数。然后，函数的响应将映射到一个 HTTP 响应，Lambda 会通过函数 URL 将该响应发送回客户端。

请求和响应事件格式遵循与 [Amazon API Gateway 有效负载格式版本 2.0](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format) 相同的模式。

### 请求有效负载格式
<a name="urls-request-payload"></a>

请求有效负载具有以下结构：

```
{
  "version": "2.0",
  "routeKey": "$default",
  "rawPath": "/my/path",
  "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
  "cookies": [
    "cookie1",
    "cookie2"
  ],
  "headers": {
    "header1": "value1",
    "header2": "value1,value2"
  },
  "queryStringParameters": {
    "parameter1": "value1,value2",
    "parameter2": "value"
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "<urlid>",
    "authentication": null,
    "authorizer": {
        "iam": {
                "accessKey": "AKIA...",
                "accountId": "111122223333",
                "callerId": "AIDA...",
                "cognitoIdentity": null,
                "principalOrgId": null,
                "userArn": "arn:aws:iam::111122223333:user/example-user",
                "userId": "AIDA..."
        }
    },
    "domainName": "<url-id>.lambda-url.us-west-2.on.aws",
    "domainPrefix": "<url-id>",
    "http": {
      "method": "POST",
      "path": "/my/path",
      "protocol": "HTTP/1.1",
      "sourceIp": "123.123.123.123",
      "userAgent": "agent"
    },
    "requestId": "id",
    "routeKey": "$default",
    "stage": "$default",
    "time": "12/Mar/2020:19:03:58 +0000",
    "timeEpoch": 1583348638390
  },
  "body": "Hello from client!",
  "pathParameters": null,
  "isBase64Encoded": false,
  "stageVariables": null
}
```


| 参数 | 描述 | 示例 | 
| --- | --- | --- | 
|  `version`  |  此事件的有效负载格式版本。Lambda 函数 URL 目前支持[有效负载格式版本 2.0](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format)。  |  `2.0`  | 
|  `routeKey`  |  函数 URL 不使用此参数。Lambda 将其设置为 `$default`，作为占位符。  |  `$default`  | 
|  `rawPath`  |  请求路径。例如，如果请求 URL 为 `https://{url-id}.lambda-url.{region}.on.aws/example/test/demo`，则原始路径值为 `/example/test/demo`。  |  `/example/test/demo`  | 
|  `rawQueryString`  |  包含请求的查询字符串参数的原始字符串。支持的字符包括 `a-z`、`A-Z`、`0-9`、`.`、`_`、`-`、`%`、`&`、`=` 和 `+`。  |  `"?parameter1=value1&parameter2=value2"`  | 
|  `cookies`  |  数组包含发送的部分请求的所有 Cookie。  |  `["Cookie_1=Value_1", "Cookie_2=Value_2"]`  | 
|  `headers`  |  请求标头的列表，以键值对的形式显示。  |  `{"header1": "value1", "header2": "value2"}`  | 
|  `queryStringParameters`  |  请求的查询参数。例如，如果请求 URL 为 `https://{url-id}.lambda-url.{region}.on.aws/example?name=Jane`，则 `queryStringParameters` 值是一个 JSON 对象，其键为 `name`，值为 `Jane`。  |  `{"name": "Jane"}`  | 
|  `requestContext`  |  一个包含有关请求的附加信息的对象，例如 `requestId`、请求的时间以及通过 AWS Identity and Access Management (IAM) 授权的调用者身份。  |   | 
|  `requestContext.accountId`  |  函数拥有者的 AWS 账户 ID。  |  `"123456789012"`  | 
|  `requestContext.apiId`  |  函数 URL 的 ID。  |  `"33anwqw8fj"`  | 
|  `requestContext.authentication`  |  函数 URL 不使用此参数。Lambda 会将其设置为 `null`。  |  `null`  | 
|  `requestContext.authorizer`  |  对象包含有关调用者身份的信息（如果函数 URL 使用 `AWS_IAM` 身份验证类型）。否则，Lambda 会将其设置为 `null`。  |   | 
|  `requestContext.authorizer.iam.accessKey`  |  调用者身份的访问密钥。  |  `"AKIAIOSFODNN7EXAMPLE"`  | 
|  `requestContext.authorizer.iam.accountId`  |  调用者身份的 AWS 账户 ID。  |  `"111122223333"`  | 
|  `requestContext.authorizer.iam.callerId`  |  调用者的 ID（用户 ID）。  |  `"AIDACKCEVSQ6C2EXAMPLE"`  | 
|  `requestContext.authorizer.iam.cognitoIdentity`  |  函数 URL 不使用此参数。Lambda 会将其设置为 `null`，或将其从 JSON 中排除。  |  `null`  | 
|  `requestContext.authorizer.iam.principalOrgId`  |  与调用者身份关联的主体企业 ID。  |  `"AIDACKCEVSQORGEXAMPLE"`  | 
|  `requestContext.authorizer.iam.userArn`  |  调用者身份的用户 Amazon 资源名称（ARN）。  |  `"arn:aws:iam::111122223333:user/example-user"`  | 
|  `requestContext.authorizer.iam.userId`  |  调用者身份的用户 ID。  |  `"AIDACOSFODNN7EXAMPLE2"`  | 
|  `requestContext.domainName`  |  函数 URL 的域名。  |  `"<url-id>.lambda-url.us-west-2.on.aws"`  | 
|  `requestContext.domainPrefix`  |  函数 URL 的域前缀。  |  `"<url-id>"`  | 
|  `requestContext.http`  |  包含有关 HTTP 请求的详细信息的对象。  |   | 
|  `requestContext.http.method`  |  此请求中使用的 HTTP 方法。有效值包括 `GET`、`POST`、`PUT`、`HEAD`、`OPTIONS`、`PATCH` 和 `DELETE`。  |  `GET`  | 
|  `requestContext.http.path`  |  请求路径。例如，如果请求 URL 为 `https://{url-id}.lambda-url.{region}.on.aws/example/test/demo`，则路径值为 `/example/test/demo`。  |  `/example/test/demo`  | 
|  `requestContext.http.protocol`  |  请求的协议。  |  `HTTP/1.1`  | 
|  `requestContext.http.sourceIp`  |  发出请求的即时 TCP 连接的源 IP 地址。  |  `123.123.123.123`  | 
|  `requestContext.http.userAgent`  |  用户代理请求标头值。  |  `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Gecko/20100101 Firefox/42.0`  | 
|  `requestContext.requestId`  |  调用请求的 ID。可以使用此 ID 跟踪与函数相关的调用日志。  |  `e1506fd5-9e7b-434f-bd42-4f8fa224b599`  | 
|  `requestContext.routeKey`  |  函数 URL 不使用此参数。Lambda 将其设置为 `$default`，作为占位符。  |  `$default`  | 
|  `requestContext.stage`  |  函数 URL 不使用此参数。Lambda 将其设置为 `$default`，作为占位符。  |  `$default`  | 
|  `requestContext.time`  |  请求的时间戳。  |  `"07/Sep/2021:22:50:22 +0000"`  | 
|  `requestContext.timeEpoch`  |  请求的时间戳，用 Unix epoch 时间表示。  |  `"1631055022677"`  | 
|  `body`  |  请求的正文。如果请求的内容类型为二进制，则正文为 base64 编码。  |  `{"key1": "value1", "key2": "value2"}`  | 
|  `pathParameters`  |  函数 URL 不使用此参数。Lambda 会将其设置为 `null`，或将其从 JSON 中排除。  |  `null`  | 
|  `isBase64Encoded`  |  如果正文为二进制有效负载，并且为 base64 编码，则为 `TRUE`。否则为 `FALSE`。  |  `FALSE`  | 
|  `stageVariables`  |  函数 URL 不使用此参数。Lambda 会将其设置为 `null`，或将其从 JSON 中排除。  |  `null`  | 

### 响应有效负载格式
<a name="urls-response-payload"></a>

当函数返回响应时，Lambda 会解析响应并将其转换为 HTTP 响应。函数响应有效负载的格式如下：

```
{
   "statusCode": 201,
    "headers": {
        "Content-Type": "application/json",
        "My-Custom-Header": "Custom Value"
    },
    "body": "{ \"message\": \"Hello, world!\" }",
    "cookies": [
        "Cookie_1=Value1; Expires=21 Oct 2021 07:48 GMT",
        "Cookie_2=Value2; Max-Age=78000"
    ],
    "isBase64Encoded": false
}
```

Lambda 会为您推断响应格式。如果您的函数返回有效的 JSON 并且没有返回 `statusCode`，Lambda 会做出以下假设：
+ `statusCode`is(`200` )
**注意**  
有效的 `statusCode` 在 100 至 599 范围内。
+ `content-type`is(`application/json` )
+ `body` 是函数响应。
+ `isBase64Encoded`is(`false` )

以下示例显示了 Lambda 函数的输出如何映射到响应有效负载，以及响应有效负载如何映射到最终 HTTP 响应。当客户端调用函数 URL 时，就会看到 HTTP 响应。

**字符串响应的输出示例**


| Lambda 函数输出 | 解释响应输出 | HTTP 响应（客户端看到的内容） | 
| --- | --- | --- | 
|  <pre>"Hello, world!"</pre>  |  <pre>{<br />  "statusCode": 200,<br />  "body": "Hello, world!",<br />  "headers": {<br />    "content-type": "application/json"<br />  },<br />  "isBase64Encoded": false<br />}</pre>  |  <pre>HTTP/2 200<br />date: Wed, 08 Sep 2021 18:02:24 GMT<br />content-type: application/json<br />content-length: 15<br /><br />"Hello, world!"</pre>  | 

**JSON 响应的输出示例**


| Lambda 函数输出 | 解释响应输出 | HTTP 响应（客户端看到的内容） | 
| --- | --- | --- | 
|  <pre>{<br />  "message": "Hello, world!"<br />}</pre>  |  <pre>{<br />  "statusCode": 200,<br />  "body": {<br />    "message": "Hello, world!"<br />  },<br />  "headers": {<br />    "content-type": "application/json"<br />  },<br />  "isBase64Encoded": false<br />}</pre>  |  <pre>HTTP/2 200<br />date: Wed, 08 Sep 2021 18:02:24 GMT<br />content-type: application/json<br />content-length: 34<br /><br />{<br />  "message": "Hello, world!"<br />}</pre>  | 

**自定义响应的输出示例**


| Lambda 函数输出 | 解释响应输出 | HTTP 响应（客户端看到的内容） | 
| --- | --- | --- | 
|  <pre>{<br />   "statusCode": 201,<br />    "headers": {<br />        "Content-Type": "application/json",<br />        "My-Custom-Header": "Custom Value"<br />    },<br />    "body": JSON.stringify({<br />        "message": "Hello, world!"<br />    }),<br />    "isBase64Encoded": false<br />}</pre>  |  <pre>{<br />   "statusCode": 201,<br />    "headers": {<br />        "Content-Type": "application/json",<br />        "My-Custom-Header": "Custom Value"<br />    },<br />    "body": JSON.stringify({<br />        "message": "Hello, world!"<br />    }),<br />    "isBase64Encoded": false<br />}</pre>  |  <pre>HTTP/2 201<br />date: Wed, 08 Sep 2021 18:02:24 GMT<br />content-type: application/json<br />content-length: 27<br />my-custom-header: Custom Value<br /><br />{<br />  "message": "Hello, world!"<br />}</pre>  | 

### Cookie
<a name="urls-cookies"></a>

要从函数返回 Cookie，请不要手动添加 `set-cookie` 标头。相反，请在响应有效负载对象中包含 Cookie。Lambda 会自动进行解释，并将其作为 `set-cookie` 标头添加到 HTTP 响应中，如下例所示。


| Lambda 函数输出 | HTTP 响应（客户端看到的内容） | 
| --- | --- | 
|  <pre>{<br />   "statusCode": 201,<br />    "headers": {<br />        "Content-Type": "application/json",<br />        "My-Custom-Header": "Custom Value"<br />    },<br />    "body": JSON.stringify({<br />        "message": "Hello, world!"<br />    }),<br />    "cookies": [<br />        "Cookie_1=Value1; Expires=21 Oct 2021 07:48 GMT",<br />        "Cookie_2=Value2; Max-Age=78000"<br />    ],<br />    "isBase64Encoded": false<br />}</pre>  |  <pre>HTTP/2 201<br />date: Wed, 08 Sep 2021 18:02:24 GMT<br />content-type: application/json<br />content-length: 27<br />my-custom-header: Custom Value<br />set-cookie: Cookie_1=Value2; Expires=21 Oct 2021 07:48 GMT<br />set-cookie: Cookie_2=Value2; Max-Age=78000<br /><br />{<br />  "message": "Hello, world!"<br />}</pre>  | 

# 监控 Lambda 函数 URL
<a name="urls-monitoring"></a>

您可以使用 AWS CloudTrail 和 Amazon CloudWatch 来监控您的函数 URL。

**Topics**
+ [使用 CloudTrail 监控函数 URL](#urls-cloudtrail)
+ [函数 URL 的 CloudWatch 指标](#urls-cloudwatch)

## 使用 CloudTrail 监控函数 URL
<a name="urls-cloudtrail"></a>

对于函数 URL，Lambda 自动支持将以下 API 操作记录为 CloudTrail 日志文件中的事件：
+ [CreateFunctionUrlConfig](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunctionUrlConfig.html)
+ [UpdateFunctionUrlConfig](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionUrlConfig.html)
+ [DeleteFunctionUrlConfig](https://docs.aws.amazon.com/lambda/latest/api/API_DeleteFunctionUrlConfig.html)
+ [GetFunctionUrlConfig](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionUrlConfig.html)
+ [ListFunctionUrlConfigs](https://docs.aws.amazon.com/lambda/latest/api/API_ListFunctionUrlConfigs.html)

每个日志条目都包含有关调用者身份、发出请求的时间以及其他详细信息的信息。通过查看 CloudTrail **Event history**（事件历史记录），可以看到过去 90 天内的所有事件。要保留过去 90 天的记录，可以创建跟踪记录。

原定设置下，CloudTrail 不会录入 `InvokeFunctionUrl` 请求，这些请求将被视为数据事件。但是，您可以在 CloudTrail 中打开数据事件日志记录。有关更多信息，请参阅 *AWS CloudTrail 用户指南*中的[记录数据事件以便跟踪](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events-with-cloudtrail.html)。

## 函数 URL 的 CloudWatch 指标
<a name="urls-cloudwatch"></a>

Lambda 会向 CloudWatch 发送关于函数 URL 请求的聚合指标。借助这些指标，您可以在 CloudWatch 控制台中监控函数 URL、构建控制面板和配置告警。

函数 URL 支持以下调用指标。我们建议使用 `Sum` 统计数据查看这些指标。
+ `UrlRequestCount` – 向该函数 URL 发出的请求数。
+ `Url4xxCount` – 返回 4XX HTTP 状态码的请求数。4XX 系列代码表示客户端错误，例如错误请求。
+ `Url5xxCount` – 返回 5XX HTTP 状态码的请求数。5XX 系列代码表示服务器端错误，例如函数错误和超时。

函数 URL 还支持以下性能指标。我们建议使用 `Average` 或 `Max` 统计数据查看此指标。
+ `UrlRequestLatency` – 函数 URL 收到请求和函数 URL 返回响应之间的时间。

每个调用和性能指标都支持以下维度：
+ `FunctionName` – 查看分配给函数 `$LATEST` 未发布版本或任何函数别名的函数 URL 的聚合指标。例如，`hello-world-function`。
+ `Resource` – 查看特定函数 URL 的指标。其由函数名称、函数的 `$LATEST` 未发布版本或函数的别名之一定义。例如，`hello-world-function:$LATEST`。
+ `ExecutedVersion` – 根据执行的版本查看特定函数 URL 的指标。您可以主要使用此维度跟踪分配给 `$LATEST` 未发布版本的函数 URL。

# 选择使用 HTTP 请求调用 Lambda 函数的方法
<a name="furls-http-invoke-decision"></a>

Lambda 的许多常见使用案例都涉及使用 HTTP 请求调用函数。例如，您可能希望 Web 应用程序通过浏览器请求调用函数。Lambda 函数还可用于创建完整的 REST API、处理来自移动应用程序的用户交互、通过 HTTP 调用处理来自外部服务的数据，或者创建自定义 Webhook。

以下几节介绍了通过 HTTP 调用 Lambda 的选择，并提供了有助于您针对特定使用案例做出正确决策的信息。

## 在选择 HTTP 调用方法时，您有什么选择？
<a name="w2aac39c81c73b9"></a>

Lambda 提供了两种使用 HTTP 请求调用函数的主要方法：[函数 URL](urls-configuration.md) 和 [API Gateway](services-apigateway.md)。这两个选项之间的主要差异如下所示：
+ **Lambda 函数 URL** 为 Lambda 函数提供了简单、直接的 HTTP 端点。它们针对简单性和成本效益进行了优化，且提供了通过 HTTP 公开 Lambda 函数的最快路径。
+ **API Gateway** 是用于构建功能齐全的 API 的更高级服务。API Gateway 针对大规模构建和管理生产 API 进行了优化，并提供了用于安全、监控和流量管理的全面工具。

## 在已经知道自己要求的情况下的建议
<a name="w2aac39c81c73c11"></a>

如果您已经明确自己的要求，则以下是我们的基本建议：

建议在简单的应用程序或原型设计中使用**[函数 URL](urls-configuration.md)**，其中您只需要基本身份验证方法和请求/响应处理，并且希望将成本和复杂性降至最低。

**[API Gateway](services-apigateway.md)** 是大规模生产应用程序或需要更高级功能的情况下的更好选择，例如 [OpenAPI 描述](https://www.openapis.org/)支持、身份验证选项选择、自定义域名或丰富的请求/响应处理（包括节流、缓存和请求/响应转换）。

## 选择用于调用 Lambda 函数的方法时要考虑的事项
<a name="w2aac39c81c73c13"></a>

在函数 URL 与 API Gateway 之间进行选择时，您需要考虑以下因素：
+ 您的身份验证需求，例如您需要 OAuth 还是 Amazon Cognito 来对用户进行身份验证
+ 您的扩展要求和要实施的 API 的复杂性
+ 您是否需要请求验证和请求/响应格式等高级功能
+ 您的监控要求
+ 您的成本目标

通过了解这些因素，您可以选择能平衡安全性、复杂性和成本要求的最佳选项。

以下信息汇总了两个选项之间的主要差异。

### 身份验证
<a name="w2aac39c81c73c13c11b1"></a>
+ **函数 URL** 通过 AWS Identity and Access Management（IAM）提供基本身份验证选项。您可以将端点配置为公有（无身份验证）或要求 IAM 身份验证。通过 IAM 身份验证，您可以使用标准 AWS 凭证或 IAM 角色来控制访问权限。虽然设置起来很简单，但与其他身份验证方法相比，此方法提供的选项有限。
+ **API Gateway** 提供对更全面的身份验证选项的访问权限。除了 IAM 身份验证外，您还可以使用 [Lambda 授权方](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html)（自定义身份验证逻辑）、[Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html) 用户池和 OAuth 2.0 流。这种灵活性使您能够实施复杂的身份验证方案，包括第三方身份验证提供商、基于令牌的身份验证和多重身份验证。

### 请求/响应处理
<a name="w2aac39c81c73c13c11b3"></a>
+ **函数 URL** 提供了基本的 HTTP 请求和响应处理。它们支持标准 HTTP 方法，并包括内置的跨源资源共享（CORS）支持。虽然它们可以自然地处理 JSON 有效载荷和查询参数，但不提供请求转换或验证功能。响应处理同样简单 – 客户端从您的 Lambda 函数接收的响应与 Lambda 返回的响应完全相同。
+ **API Gateway** 提供了高级的请求和响应处理功能。您可以定义请求验证器、使用映射模板转换请求和响应、设置请求/响应标头，以及实施响应缓存。API Gateway 还支持二进制有效载荷和自定义域名，并且可以在响应到达客户端之前对其修改。您可以通过使用 JSON 架构来为请求/响应验证和转换设置模型。

### 扩展
<a name="w2aac39c81c73c13c11b5"></a>
+ **函数 URL** 可直接根据您的 Lambda 函数的并发限制进行扩展，并通过将函数扩展到其配置的最大并发限制来处理流量激增。达到该限制后，Lambda 将使用 HTTP 429 响应来响应其他请求。由于没有内置的队列机制，因此处理扩展完全取决于您的 Lambda 函数的配置。默认情况下，Lambda 函数每个 AWS 区域的并发执行限制为 1000 次。
+ **API Gateway** 在 Lambda 自己的扩展基础上提供了额外的扩展功能。其中包括内置的请求队列和节流控制，使您可以更妥善地管理流量激增。默认情况下，API Gateway 每个区域每秒最多可以处理 1 万个请求，容量爆增为每秒 5000 个请求。还提供了在不同级别（API、阶段或方法）限制请求的工具，以保护您的后端。

### 监控
<a name="w2aac39c81c73c13c11b7"></a>
+ **函数 URL** 通过 Amazon CloudWatch 指标来提供基本监控，包括请求计数、延迟和错误率。您可以访问标准 Lambda 指标和日志，它们显示了进入函数的原始请求。虽然这提供了基本的运营可见性，但这些指标主要侧重于函数执行。
+ **API Gateway** 提供全面的监控功能，其中包括详细的指标、日志记录和跟踪选项。您可以通过 CloudWatch 监控 API 调用、延迟、错误率和缓存命中/未命中率。API Gateway 还与 AWS X-Ray 集成，用于分布式跟踪，并提供可自定义的日志记录格式。

### 成本
<a name="w2aac39c81c73c13c11b9"></a>
+ **函数 URL** 遵循标准 Lambda 定价模型 – 您只需按函数调用和计算时间付费。URL 端点本身不收取额外费用。如果您不需要 API Gateway 的其他功能，则会使其成为简单 API 或低流量应用程序的经济实惠之选。
+ **API Gateway** 提供[免费套餐](https://aws.amazon.com/api-gateway/pricing/#Free_Tier)，其中包括为 REST API 接收的一百万次 API 调用和为 HTTP API 接收的一百万次 API 调用。此后，API Gateway 将对 API 调用、数据传输和缓存（如果已启用）收费。请参阅 API Gateway [定价页面](https://aws.amazon.com/api-gateway/pricing/)，了解您自己的使用案例的成本。

### 其他功能
<a name="w2aac39c81c73c13c11c11"></a>
+ **函数 URL** 旨在实现简单性以及 Lambda 直接集成。它们同时支持 HTTP 和 HTTPS 端点，提供内置的 CORS 支持，并提供双堆栈（IPv4 和 IPv6）端点。虽然它们缺乏高级功能，但在需要以快速、直接的方式通过 HTTP 公开 Lambda 函数的场景中，它们表现出色。
+ **API Gateway** 包括许多其他功能，例如 API 版本控制、阶段管理、使用计划的 API 密钥、通过 Swagger/OpenAPI 提供的 API 文档、WebSocket API、VPC 内的私有 API，以及用于提高安全性的 WAF 集成。它还支持金丝雀部署、用于测试的模拟集成以及与 Lambda 之外的其他 AWS 服务的集成。

## 选择调用 Lambda 函数的方法
<a name="w2aac39c81c73c15"></a>

现在，您已经了解了在 Lambda 函数 URL 与 API Gateway 之间进行选择的标准以及它们之间的主要区别，您可以选择最符合您需求的选项，并使用以下资源来帮助您开始使用它。

------
#### [ Function URLs ]

**通过以下资源开始使用函数 URL**
+ 按照[使用函数 URL 创建 Lambda 函数](urls-webhook-tutorial.md)教程进行操作
+ 在本指南的[创建和管理 Lambda 函数 URL](urls-configuration.md) 章节中了解有关函数 URL 的更多信息
+ 通过执行以下操作，尝试控制台内指导教程**创建简单的 Web 应用程序**：

1. 打开 Lamba 控制台的[函数页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择屏幕右上角的图标打开帮助面板。  
![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/console_help_screenshot.png)

1. 选择**教程**。

1. 在**创建简单的 Web 应用程序**中，选择**开始教程**。

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

**通过以下资源开始使用 Lambda 和 API Gateway**
+ 按照[利用 API Gateway 使用 Lambda](services-apigateway-tutorial.md) 教程，创建与后端 Lambda 函数集成的 REST API。
+ 要详细了解 API Gateway 提供的不同类型 API，请参阅《Amazon API Gateway 开发人员指南》**的以下部分：
  + [API Gateway REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html)
  + [API Gateway HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html)
  + [API Gateway WebSocket API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html)
+ 试用《Amazon API Gateway 开发人员指南》**的[教程和研讨会](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-tutorials.html)部分中的一个或多个示例。

------

# 教程：使用 Lambda 函数 URL 创建 Webhooook 端点
<a name="urls-webhook-tutorial"></a>

在本教程中，您将创建 Lambda 函数 URL 来实现 Webhooook 端点。Webhook 是一种轻量级、事件驱动的通信，其使用 HTTP 在应用程序之间自动发送数据。您可以使用 Webhook 接收有关在其他系统中发生的事件的即时更新，例如网站上有新客户注册、处理付款或上传文件时。

通过 Lambda，可以使用 Lambda 函数 URL 或 API Gateway 实现网络挂钩。对于不需要高级授权或请求验证等功能的简单 Webhook 来说，函数 URL 是一个不错的选择。

**提示**  
如果您不确定哪种解决方案最适合您的特定用例，请参阅[选择使用 HTTP 请求调用 Lambda 函数的方法](furls-http-invoke-decision.md)。

## 先决条件
<a name="urls-webhook-tutorial-prereqs"></a>

要完成本教程，您必须在本地计算机上安装 Python（版本 3.8 或更高版本）或 Node.js（版本 18 或更高版本）。

为使用 HTTP 请求测试端点，本教程使用了 [curl](https://curl.se/)，这是一种命令行工具，您可以使用它来通过各种网络协议传输数据。如果您还没有安装该工具，则请参阅 [curl 文档](https://curl.se/docs/install.html)以了解如何安装该工具。

## 创建 Lambda 函数
<a name="urls-webhook-tutorial-function"></a>

首先创建 Lambda 函数，在将 HTTP 请求发送到 Webhooook 端点时会运行该函数。在此示例中，每当提交付款时，发送应用程序都会发送更新，并在 HTTP 请求的正文中指示付款是否成功。Lambda 函数会解析该请求并根据付款状态采取行动。在此示例中，代码仅打印付款的订单 ID，但在实际应用程序中，您可以将订单添加到数据库或发送通知。

该函数还实现了用于 Webhook 的最常见的身份验证方法，即基于哈希的消息身份验证（HMAC）。使用这种方法，发送和接收应用程序共享一个密钥。发送应用程序使用哈希算法将此密钥与消息内容一起生成唯一签名，并将该签名作为 HTTP 标头包含在 Webhook 请求中。然后，接收应用程序会重复此步骤，使用密钥生成签名，并将结果值与请求标头中发送的签名进行比较。如果结果匹配，则该请求被视为合法。

将 Lambda 控制台与 Python 或 Node.js 运行时一起使用创建该函数。

------
#### [ Python ]

**创建 Lambda 函数**

1. 打开 Lamba 控制台的 [Functions](https://console.aws.amazon.com/lambda/home#/functions)（函数）页面。

1. 通过执行以下操作创建基本“Hello world”函数：

   1. 选择**创建函数**。

   1. 选择**从头开始编写**。

   1. 对于**函数名称**，请输入 **myLambdaWebhook**。

   1. 对于**运行时**，选择 **python3.14**。

   1. 选择**创建函数**。

1. 在**代码源**窗格中，通过复制并粘贴以下内容替换现有代码：

   ```
   import json
   import hmac
   import hashlib
   import os
   
   def lambda_handler(event, context):
       
       # Get the webhook secret from environment variables
       webhook_secret = os.environ['WEBHOOK_SECRET']
       
       # Verify the webhook signature
       if not verify_signature(event, webhook_secret):
           return {
               'statusCode': 401,
               'body': json.dumps({'error': 'Invalid signature'})
           }
       
       try:
           # Parse the webhook payload
           payload = json.loads(event['body'])
           
           # Handle different event types
           event_type = payload.get('type')
           
           if event_type == 'payment.success':
               # Handle successful payment
               order_id = payload.get('orderId')
               print(f"Processing successful payment for order {order_id}")
               
               # Add your business logic here
               # For example, update database, send notifications, etc.
               
           elif event_type == 'payment.failed':
               # Handle failed payment
               order_id = payload.get('orderId')
               print(f"Processing failed payment for order {order_id}")
               
               # Add your business logic here
               
           else:
               print(f"Received unhandled event type: {event_type}")
           
           # Return success response
           return {
               'statusCode': 200,
               'body': json.dumps({'received': True})
           }
           
       except json.JSONDecodeError:
           return {
               'statusCode': 400,
               'body': json.dumps({'error': 'Invalid JSON payload'})
           }
       except Exception as e:
           print(f"Error processing webhook: {e}")
           return {
               'statusCode': 500,
               'body': json.dumps({'error': 'Internal server error'})
           }
   
   def verify_signature(event, webhook_secret):
       """
       Verify the webhook signature using HMAC
       """
       try:
           # Get the signature from headers
           signature = event['headers'].get('x-webhook-signature')
   
           if not signature:
               print("Error: Missing webhook signature in headers")
               return False
           
           # Get the raw body (return an empty string if the body key doesn't exist)
           body = event.get('body', '')
           
           # Create HMAC using the secret key
           expected_signature = hmac.new(
               webhook_secret.encode('utf-8'),
               body.encode('utf-8'),
               hashlib.sha256
           ).hexdigest()
           
           # Compare the expected signature with the received signature to authenticate the message
           is_valid = hmac.compare_digest(signature, expected_signature)
           if not is_valid:
               print(f"Error: Invalid signature. Received: {signature}, Expected: {expected_signature}")
               return False
               
           return True
       except Exception as e:
           print(f"Error verifying signature: {e}")
           return False
   ```

1. 在**部署**部分，选择**部署**以更新函数的代码。

------
#### [ Node.js ]

**创建 Lambda 函数**

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 通过执行以下操作创建基本“Hello world”函数：

   1. 选择**创建函数**。

   1. 选择**从头开始编写**。

   1. 对于**函数名称**，请输入 **myLambdaWebhook**。

   1. 对于**运行时**，选择 **nodejs24.x**。

   1. 选择**创建函数**。

1. 在**代码源**窗格中，通过复制并粘贴以下内容替换现有代码：

   ```
   import crypto from 'crypto';
   
   export const handler = async (event, context) => {
       // Get the webhook secret from environment variables
       const webhookSecret = process.env.WEBHOOK_SECRET;
   
       // Verify the webhook signature
       if (!verifySignature(event, webhookSecret)) {
           return {
               statusCode: 401,
               body: JSON.stringify({ error: 'Invalid signature' })
           };
       }
   
       try {
           // Parse the webhook payload
           const payload = JSON.parse(event.body);
   
           // Handle different event types
           const eventType = payload.type;
   
           switch (eventType) {
               case 'payment.success': {
                   // Handle successful payment
                   const orderId = payload.orderId;
                   console.log(`Processing successful payment for order ${orderId}`);
   
                   // Add your business logic here
                   // For example, update database, send notifications, etc.
                   break;
               }
   
               case 'payment.failed': {
                   // Handle failed payment
                   const orderId = payload.orderId;
                   console.log(`Processing failed payment for order ${orderId}`);
   
                   // Add your business logic here
                   break;
               }
   
               default:
                   console.log(`Received unhandled event type: ${eventType}`);
           }
   
           // Return success response
           return {
               statusCode: 200,
               body: JSON.stringify({ received: true })
           };
   
       } catch (error) {
           if (error instanceof SyntaxError) {
               // Handle JSON parsing errors
               return {
                   statusCode: 400,
                   body: JSON.stringify({ error: 'Invalid JSON payload' })
               };
           }
   
           // Handle all other errors
           console.error('Error processing webhook:', error);
           return {
               statusCode: 500,
               body: JSON.stringify({ error: 'Internal server error' })
           };
       }
   };
   
   // Verify the webhook signature using HMAC
   
   const verifySignature = (event, webhookSecret) => {
       try {
           // Get the signature from headers
           const signature = event.headers['x-webhook-signature'];
     
           if (!signature) {
               console.log('No signature found in headers:', event.headers);
               return false;
           }
     
           // Get the raw body (return an empty string if the body key doesn't exist)
           const body = event.body || '';
     
           // Create HMAC using the secret key
           const hmac = crypto.createHmac('sha256', webhookSecret);
           const expectedSignature = hmac.update(body).digest('hex');
     
           // Compare expected and received signatures
           const isValid = signature === expectedSignature;
           if (!isValid) {
               console.log(`Invalid signature. Received: ${signature}, Expected: ${expectedSignature}`);
               return false;
           }
           
           return true;
       } catch (error) {
           console.error('Error during signature verification:', error);
           return false;
       }
     };
   ```

1. 在**部署**部分，选择**部署**以更新函数的代码。

------

## 创建密钥
<a name="urls-webhook-tutorial-key"></a>

为了让 Lambda 函数对 Webhook 请求进行身份验证，其使用与调用应用程序共享的密钥。在此示例中，密钥存储在环境变量中。在生产应用程序中，切勿在函数代码中包含密码等敏感信息。相反，[创建一个 AWS Secrets Manager 密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)，然后[使用 AWS 参数和密钥 Lambda 扩展](with-secrets-manager.md)在 Lambda 函数中检索您的凭证。

**创建并存储 Webhook 密钥**

1. 使用加密安全随机数生成器生成一个随机的长字符串。您可以在 Python 或 Node.js 中使用以下代码片段来生成并打印一个 32 个字符的密钥，也可以使用自己的首选方法。

------
#### [ Python ]

**Example 生成密钥的代码**  

   ```
   import secrets
   webhook_secret = secrets.token_urlsafe(32)
   print(webhook_secret)
   ```

------
#### [ Node.js ]

**Example 生成密钥的代码（ES 模块格式）**  

   ```
   import crypto from 'crypto';
   let webhookSecret = crypto.randomBytes(32).toString('base64');
   console.log(webhookSecret)
   ```

------

1. 通过执行以下操作，将生成的字符串存储为函数的环境变量：

   1. 在函数的**配置**选项卡中，选择**环境变量**。

   1. 选择**编辑**。

   1. 选择**添加环境变量**。

   1. 在**键**中输入 **WEBHOOK\$1SECRET**，然后在**值**中输入您在上一步生成的密钥。

   1. 选择**保存**。

您将需要在本教程后面的部分中再次使用此密钥来测试函数，因此请现在记下该密钥。

## 创建函数 URL 端点
<a name="urls-webhook-tutorial-furl"></a>

使用 Lambda 函数 URL 为您的 Webhook 创建端点。由于您使用身份验证类型 `NONE` 来创建具有公共访问权限的端点，因此任何人都可以通过该 URL 调用您的函数。要了解有关控制函数 URL 访问权限的更多信息，请参阅[控制对 Lambda 函数 URL 的访问](urls-auth.md)。如果您的 Webhook 需要更多高级身份验证选项，请考虑使用 API Gateway。

**创建函数 URL 端点**

1. 在函数的**配置**选项卡中，选择**函数 URL**。

1. 选择 **Create function URL**（创建函数 URL）。

1. 对于**身份验证类型**，选择**无**。

1. 选择**保存**。

您刚刚创建的函数 URL 的端点将在**函数 URL** 窗格中显示。复制此端点以在本教程后面的部分中使用。

## 在控制台中测试函数
<a name="urls-webhook-tutorial-test-console"></a>

在使用 HTTP 请求通过 URL 端点调用您的函数之前，请在控制台中对其进行测试，以确认您的代码按预期工作。

要在控制台中验证该函数，请首先使用本教程前面的部分中生成的密钥计算一个 Webhook 签名，其中包含以下测试 JSON 有效载荷：

```
{
    "type": "payment.success", 
    "orderId": "1234",
    "amount": "99.99"
}
```

使用以下任一 Python 或 Node.js 代码示例，采用您自己的密钥计算 Webhook 签名。

------
#### [ Python ]

**计算 Webhook 签名**

1. 将以下代码另存为名为 `calculate_signature.py` 的文件。将该代码中的 Webhooook 密钥替换为您自己的值。

   ```
   import secrets
   import hmac
   import json
   import hashlib
   
   webhook_secret = "arlbSDCP86n_1H90s0fL_Qb2NAHBIBQOyGI0X4Zay4M"
   
   body = json.dumps({"type": "payment.success", "orderId": "1234", "amount": "99.99"})
   
   signature = hmac.new(
               webhook_secret.encode('utf-8'),
               body.encode('utf-8'),
               hashlib.sha256
           ).hexdigest()
   
   print(signature)
   ```

1. 通过从保存该代码的同一目录运行以下命令来计算签名。复制该代码输出的签名。

   ```
   python calculate_signature.py
   ```

------
#### [ Node.js ]

**计算 Webhook 签名**

1. 将以下代码另存为名为 `calculate_signature.mjs` 的文件。将该代码中的 Webhooook 密钥替换为您自己的值。

   ```
   import crypto from 'crypto';
   
   const webhookSecret = "arlbSDCP86n_1H90s0fL_Qb2NAHBIBQOyGI0X4Zay4M"
   const body = "{\"type\": \"payment.success\", \"orderId\": \"1234\", \"amount\": \"99.99\"}";
   
   let hmac = crypto.createHmac('sha256', webhookSecret);
   let signature = hmac.update(body).digest('hex');
   
   console.log(signature);
   ```

1. 通过从保存该代码的同一目录运行以下命令来计算签名。复制该代码输出的签名。

   ```
   node calculate_signature.mjs
   ```

------

现在，您可以在控制台中使用测试 HTTP 请求测试您的函数代码。

**在控制台中测试函数**

1. 为您的函数选择**代码**选项卡。

1. 在**测试事件**部分中，选择**创建新测试事件**。

1. 对于 **Event Name (事件名称)**，输入 **myEvent**。

1. 通过将以下内容复制并粘贴到**事件 JSON** 窗格中来替换现有 JSON。将 Webhooook 签名替换为您在上一步中计算得出的值。

   ```
   {
     "headers": {
       "Content-Type": "application/json",
       "x-webhook-signature": "2d672e7a0423fab740fbc040e801d1241f2df32d2ffd8989617a599486553e2a"
     },
     "body": "{\"type\": \"payment.success\", \"orderId\": \"1234\", \"amount\": \"99.99\"}"
   }
   ```

1. 选择**保存**。

1. 选择**调用**。

   您应该可以看到类似于如下所示的输出内容：

------
#### [ Python ]

   ```
   Status: Succeeded
   Test Event Name: myEvent
   
   Response:
   {
     "statusCode": 200,
     "body": "{\"received\": true}"
   }
   
   Function Logs:
   START RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6 Version: $LATEST
   Processing successful payment for order 1234
   END RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6
   REPORT RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6	Duration: 1.55 ms	Billed Duration: 2 ms	Memory Size: 128 MB	Max Memory Used: 36 MB	Init Duration: 136.32 ms
   ```

------
#### [ Node.js ]

   ```
   Status: Succeeded
   Test Event Name: myEvent
   
   Response:
   {
     "statusCode": 200,
     "body": "{\"received\":true}"
   }
   
   Function Logs:
   START RequestId: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4 Version: $LATEST
   2025-01-10T18:05:42.062Z	e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4	INFO	Processing successful payment for order 1234
   END RequestId: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4
   REPORT RequestId: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4	Duration: 60.10 ms	Billed Duration: 61 ms	Memory Size: 128 MB	Max Memory Used: 72 MB	Init Duration: 174.46 ms
   
   Request ID: e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4
   ```

------

## 使用 HTTP 请求测试函数
<a name="urls-webhook-tutorial-test-curl"></a>

使用 curl 命令行工具测试您的 Webhook 端点。

**使用 HTTP 请求测试函数**

1. 在终端或 shell 程序中，运行以下 curl 命令。将该 URL 替换为您自己函数 URL 端点的值，并将 Webhook 签名替换为您使用自己的密钥计算得出的签名。

   ```
   curl -X POST https://ryqgmbx5xjzxahif6frvzikpre0bpvpf.lambda-url.us-west-2.on.aws/ \
   -H "Content-Type: application/json" \
   -H "x-webhook-signature: d5f52b76ffba65ff60ea73da67bdf1fc5825d4db56b5d3ffa0b64b7cb85ef48b" \
   -d '{"type": "payment.success", "orderId": "1234", "amount": "99.99"}'
   ```

   您应看到以下输出：

   ```
   {"received": true}
   ```

1. 通过执行以下操作，检查函数的 CloudWatch 日志，确认其是否已正确解析有效载荷：

   1. 在 Amazon CloudWatch 控制台中，打开[日志组](https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups)页面。

   1. 选择函数的日志组（`/aws/lambda/myLambdaWebhook`）。

   1. 选择最新的日志流。

      您应该可以在函数的日志中看到类似于如下所示的输出内容：

------
#### [ Python ]

      ```
      Processing successful payment for order 1234
      ```

------
#### [ Node.js ]

      ```
      2025-01-10T18:05:42.062Z e54fe6c7-1df9-4f05-a4c4-0f71cacd64f4 INFO Processing successful payment for order 1234
      ```

------

1. 运行以下 curl 命令，确认您的代码检测到无效的签名。将该 URL 替换为您自己的函数 URL 端点。

   ```
   curl -X POST https://ryqgmbx5xjzxahif6frvzikpre0bpvpf.lambda-url.us-west-2.on.aws/ \
   -H "Content-Type: application/json" \
   -H "x-webhook-signature: abcdefg" \
   -d '{"type": "payment.success", "orderId": "1234", "amount": "99.99"}'
   ```

   您应看到以下输出：

   ```
   {"error": "Invalid signature"}
   ```

## 清除资源
<a name="urls-webhook-tutorial-cleanup"></a>

除非您想要保留为本教程创建的资源，否则可立即将其删除。通过删除您不再使用的 AWS 资源，可防止您的 AWS 账户 产生不必要的费用。

**删除 Lambda 函数**

1. 打开 Lamba 控制台的 [Functions（函数）页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择您创建的函数。

1. 依次选择**操作**和**删除**。

1. 在文本输入字段中键入 **confirm**，然后选择**删除**。

在控制台中创建 Lambda 函数时，Lambda 还会为您的函数创建一个[执行角色](lambda-intro-execution-role.md)。

**删除执行角色**

1. 打开 IAM 控制台的[角色页面](https://console.aws.amazon.com/iam/home#/roles)。

1. 选择 Lambda 创建的执行角色。该角色的名称格式为 `myLambdaWebhook-role-<random string>`。

1. 选择**删除**。

1. 在文本输入字段中输入角色名称，然后选择**删除**。