

# 在 API Gateway 中对 REST API 使用阶段变量
<a name="stage-variables"></a>

阶段变量是可以定义为与 REST API 部署阶段关联的配置属性的键-值对。它们与环境变量的功能类似，可用于 API 设置和映射模板。利用 API Gateway 中的部署阶段，可以管理每个 API 的多个发布阶段；利用阶段变量，您可以将 API 部署阶段配置为与不同的后端端点进行交互。

阶段变量不适用于敏感数据，例如凭证。要将敏感数据传递给集成，请使用 AWS Lambda 授权方。您可以在 Lambda 授权方的输出中将敏感数据传递给集成。要了解更多信息，请参阅“[来自 API Gateway Lambda 授权方的输出](api-gateway-lambda-authorizer-output.md)”。

## 阶段变量的使用案例
<a name="use-cases"></a>

以下是阶段变量的使用案例。

**指定其他后端端点**  
您的 API 可以将 `GET` 请求作为 HTTP 代理传递给后端 Web 主机。您可以使用阶段变量，以使得在 API 调用方调用生产端点时，API Gateway 调用 `example.com`。之后，当 API 调用方调用 beta 阶段时，API Gateway 会调用其他 Web 主机，例如 `beta.example.com`。同样，阶段变量可用于为 API 中的每个阶段指定不同的 AWS Lambda 函数名称。您不能使用阶段变量来设置其他集成端点，例如，在一个阶段将 `GET` 请求指向 HTTP 代理集成，并在另一个阶段将该请求指向 Lambda 代理集成。  
将 Lambda 函数名称指定为阶段变量值时，您必须手动配置对 Lambda 函数的权限。当您在 API Gateway 控制台中指定 Lambda 函数时，将弹出一条 AWS CLI 命令，让您配置正确的权限。您也可以使用以下 AWS CLI 命令来执行此操作。  

```
aws lambda add-permission --function-name "arn:aws:lambda:us-east-2:123456789012:function:my-function" --source-arn "arn:aws:execute-api:us-east-2:123456789012:api_id/*/HTTP_METHOD/resource" --principal apigateway.amazonaws.com --statement-id apigateway-access --action lambda:InvokeFunction
```

**使用映射模板传递信息**  
您还可以访问映射模板中的阶段变量，或者将配置参数传递给 AWS Lambda 或 HTTP 后端。例如，您可能需要针对 API 中的多个阶段重复使用同一个 Lambda 函数，但是该函数应根据阶段，从不同的 Amazon DynamoDB 表中读取数据。在为 Lambda 函数生成请求的映射模板中，您可以使用阶段变量来将表的名称传递给 Lambda。

要使用阶段变量，首先要配置阶段变量，然后为其分配值。例如，要自定义 HTTP 集成端点，请先创建 `url` 阶段变量，然后在 API 的集成请求中输入阶段变量值 **http://\$1\$1stageVariables.url\$1**。此值将指示 API Gateway 在运行时替换您的阶段变量 `${}`，具体取决于 API 正在哪个阶段运行。有关更多信息，请参阅[为 API Gateway 中的 REST API 设置阶段变量](how-to-set-stage-variables-aws-console.md)。

# 为 API Gateway 中的 REST API 设置阶段变量
<a name="how-to-set-stage-variables-aws-console"></a>

此部分介绍如何使用 Amazon API Gateway 控制台为示例 API 的两个部署阶段设置阶段变量。要了解如何在 API Gateway 中使用阶段变量，建议您按照此部分中的所有过程进行操作。

## 先决条件
<a name="how-to-set-stage-variables-aws-console-prerequisites"></a>

在您开始之前，确保您满足以下先决条件：
+ API Gateway 中必须有可用的 API。按照中的说明进行操作[开发 API Gateway 中的 REST API](rest-api-develop.md)
+ 您必须至少部署过一次 API。按照中的说明进行操作[在 API Gateway 中部署 REST API。](how-to-deploy-api.md)
+ 您必须为已部署的 API 创建了第一个阶段。按照中的说明进行操作[创建新阶段](set-up-stages.md#how-to-create-stage-console)

  

## 使用阶段变量通过 API 调用 HTTP 端点
<a name="how-to-set-stage-variables-aws-console-http-endpoint"></a>

此过程介绍如何为 HTTP 端点创建阶段变量以及如何为 API 创建两个阶段。此外，您可以创建在此部分的以下过程中使用的阶段变量 `url`、`stageName` 和 `function`。

**使用阶段变量通过 API 调用 HTTP 端点**

1. 通过以下网址登录到 Amazon API Gateway 控制台：[https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)。

1. 创建 API，然后在 API 的根资源上创建 `GET` 方法。将集成类型设置为 **HTTP**，并将**端点 URL** 设置为 **http://\$1\$1stageVariables.url\$1**。

1. 将 API 部署到名为 **beta** 的新阶段。

1. 在主导航窗格中，选择**阶段**，然后选择 **beta** 阶段。

1. 在**阶段变量**选项卡上，选择**编辑**。

1. 选择**添加阶段变量**。

1. 对于**名称**，请输入 **url**。对于**值**，输入 **httpbin.org/get**。

1. 选择**添加阶段变量**，然后执行以下操作：

   对于**名称**，请输入 **stageName**。对于**值**，输入 **beta**。

1. 选择**添加阶段变量**，然后执行以下操作：

   对于**名称**，请输入 **function**。对于**值**，输入 **HelloWorld**。

1. 选择**保存**。

1.  现在创建第二个阶段。从**阶段**导航窗格中，选择**创建阶段**。对于**阶段名称**，输入 **prod**。从**部署**中选择一个新近部署，然后选择**创建阶段**。

1.  与 **beta** 阶段一样，将相同的三个阶段变量（**url**、**stageName** 和 **function**）分别设置为不同的值（**petstore-demo-endpoint.execute-api.com/petstore/pets**、**prod** 和 **HelloEveryone**）。

1. 在**阶段**导航窗格中，选择 **beta** 阶段。在**阶段详细信息**下，选择复制图标以复制 API 的调用 URL，然后在 Web 浏览器中输入 API 的调用 URL。这将启动 API 根资源上的 **beta** 阶段 `GET` 请求。
**注意**  
**Invoke URL** 链接指向 API 在其 **beta** 阶段的根资源。在 Web 浏览器中输入 URL 会对根资源调用 **beta** 阶段 `GET` 方法。如果方法是在子资源而非根资源本身上定义的，则在 Web 浏览器中输入 URL 将返回 `{"message":"Missing Authentication Token"}` 错误响应。在这种情况下，您必须将特定子资源的名称附加到**调用 URL** 链接。

1. **beta** 阶段 `GET` 请求的响应如下所示。您还可以使用浏览器导航到 **http://httpbin.org/get**，以验证结果。此值已分配到 **beta** 阶段中的 `url` 变量。这两个响应完全相同。

1. 在**阶段**导航窗格中，选择 **prod** 阶段。在**阶段详细信息**下，选择复制图标以复制 API 的调用 URL，然后在 Web 浏览器中输入 API 的调用 URL。这将启动 API 根资源上的 **prod** 阶段 `GET` 请求。

1. **prod** 阶段 `GET` 请求的响应如下所示。您可以使用浏览器导航到 **http://petstore-demo-endpoint.execute-api.com/petstore/pets**，以验证结果。此值已分配到 **prod** 阶段中的 `url` 变量。这两个响应完全相同。

## 将特定于阶段的元数据传入 HTTP 后端
<a name="how-to-set-stage-variables-aws-console-stage-metadata"></a>

此过程介绍如何在查询参数表达式中使用阶段变量值将特定于阶段的元数据传递到 HTTP 后端。我们将使用上一个过程中声明的 `stageName` 阶段变量。

**将特定于阶段的元数据传入 HTTP 后端**

1. 在**资源**导航窗格中，选择 **GET** 方法。

   要向方法的 URL 添加查询字符串参数，请选择**方法请求**选项卡，然后在**方法请求设置**部分中选择**编辑**。

1. 选择 **URL 查询字符串参数**并执行以下操作：

   1. 选择**添加查询字符串**。

   1. 在**名称**中，输入 **stageName**。

   1. 保持**必填**和**缓存**为已关闭状态。

1. 选择**保存**。

1. 选择**集成请求**选项卡，然后在**集成请求设置**部分中，选择**编辑**。

1. 对于**端点 URL**，将 **?stageName=\$1\$1stageVariables.stageName\$1** 附加到先前定义的 URL 值，因此整个**端点 URL** 为 **http://\$1\$1stageVariables.url\$1?stageName=\$1\$1stageVariables.stageName\$1**。

1. 选择**部署 API**，然后选择 **beta** 阶段。

1. 在主导航窗格中，选择**阶段**。在**阶段**导航窗格中，选择 **beta** 阶段。在**阶段详细信息**下，选择复制图标以复制 API 的调用 URL，然后在 Web 浏览器中输入 API 的调用 URL。
**注意**  
 我们之所以在这里使用测试阶段，是因为 HTTP 端点（由 `url` 变量“http://httpbin.org/get”指定）接受查询参数表达式，并在响应中将其作为 `args` 对象返回。

1. 您将收到以下响应。注意，分配给 `beta` 阶段变量的 `stageName` 作为 `stageName` 参数传递到后端。

      
![\[使用 url 阶段变量通过 HTTP 端点从 API 的 GET 方法获取响应。\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/stageVariables-new-console-invoke-beta-stage-with-url-and-stageName-response.png)

## 使用阶段变量通过 API 调用 Lambda 函数
<a name="how-to-set-stage-variables-aws-console-lambda-function"></a>

此过程介绍了如何使用阶段变量调用 Lambda 函数作为 API 后端。您使用已在[使用阶段变量通过 API 调用 HTTP 端点](#how-to-set-stage-variables-aws-console-http-endpoint)中声明的 `function` 阶段变量。

 在将 Lambda 函数设置为阶段变量的值时，请使用函数的本地名称，可能包括其别名或版本规范，例如 **HelloWorld**、**HelloWorld:1** 或 **HelloWorld:alpha**。请勿使用该函数的 ARN（例如 **arn:aws:lambda:us-east-1:123456789012:function:HelloWorld**）。API Gateway 控制台将 Lambda 函数的阶段变量值假定为非限定的函数名称，并且会将给定的阶段变量扩展到 ARN 中。

**使用阶段变量通过 API 调用 Lambda 函数**

1. 使用默认 Node.js 运行时系统创建名为 **HelloWorld** 的 Lambda 函数。代码必须包含以下内容：

   ```
   export const handler = function(event, context, callback) {
       if (event.stageName)
           callback(null, 'Hello, World! I\'m calling from the ' + event.stageName + ' stage.');
       else
           callback(null, 'Hello, World! I\'m not sure where I\'m calling from...');
   };
   ```

   有关如何创建 Lambda 函数的更多信息，请参阅 [REST API 控制台入门](getting-started-rest-new-console.md#getting-started-rest-new-console-create-function)。

1. 在**资源**窗格中，选择**创建资源**，然后执行以下操作：

   1. 对于**资源路径**，选择 **/**。

   1. 对于**资源名称**，输入 **lambdav1**。

   1. 选择**创建资源**。

1. 选择 **/lambdav1** 资源，然后选择**创建方法**。

   然后执行以下操作：

   1. 对于**方法类型**，选择 **GET**。

   1. 对于**集成类型**，选择 **Lambda 函数**。

   1. 保持 **Lambda 代理集成**处于关闭状态。

   1. 对于 **Lambda 函数**，输入 `${stageVariables.function}`。  
![\[按照 function 阶段变量指定的方式，创建与 Lambda 函数集成的 GET 方法。\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/stageVariables-new-console-create-lambda-get-method.png)
**提示**  
当提示使用**添加权限命令**时，复制 [add-permission](https://docs.aws.amazon.com/cli/latest/reference/lambda/add-permission.html) 命令。对将分配给 `function` 阶段变量的每个 Lambda 函数运行此命令。例如，如果 `$stageVariables.function` 值为 `HelloWorld`，则运行以下 AWS CLI 命令：  

      ```
      aws lambda add-permission --function-name arn:aws:lambda:us-east-1:account-id:function:HelloWorld --source-arn arn:aws:execute-api:us-east-1:account-id:api-id/*/GET/lambdav1 --principal apigateway.amazonaws.com --statement-id statement-id-guid --action lambda:InvokeFunction
      ```
 否则会导致在调用该方法时出现 `500 Internal Server Error` 响应。将 `${stageVariables.function}` 替换为已分配给阶段变量的 Lambda 函数名称。  
   

![\[AWS CLI 命令，以便添加针对要由您创建的方法调用的 Lambda 函数的权限。\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/stageVariables-new-console-add-permission-to-lambda-function.png)


   1. 选择**创建方法**。

1. 将 API 部署到 **prod** 和 **beta** 阶段。

1. 在主导航窗格中，选择**阶段**。在**阶段**导航窗格中，选择 **beta** 阶段。在**阶段详细信息**下，选择复制图标以复制 API 的调用 URL，然后在 Web 浏览器中输入 API 的调用 URL。在按 Enter 之前，将 **/lambdav1** 附加到 URL。

   您将收到以下响应。

   ```
   "Hello, World! I'm not sure where I'm calling from..."
   ```

## 通过阶段变量将特定于阶段的元数据传递到 Lambda 函数中
<a name="pass-version-info-to-lambda-backend-with-stage-variable"></a>

此过程介绍了如何使用阶段变量将特定于阶段的配置元数据传递到 Lambda 函数中。您创建 `POST` 方法和输入映射模板，以使用先前声明的 `stageName` 阶段变量生成负载。

**通过阶段变量将特定于阶段的元数据传递到 Lambda 函数中**

1. 选择 **/lambdav1** 资源，然后选择**创建方法**。

   然后执行以下操作：

   1. 对于**方法类型**，选择 **POST**。

   1. 对于**集成类型**，选择 **Lambda 函数**。

   1. 保持 **Lambda 代理集成**处于关闭状态。

   1. 对于 **Lambda 函数**，输入 `${stageVariables.function}`。

   1. 当提示使用**添加权限命令**时，复制 [add-permission](https://docs.aws.amazon.com/cli/latest/reference/lambda/add-permission.html) 命令。对将分配给 `function` 阶段变量的每个 Lambda 函数运行此命令。

   1. 选择**创建方法**。

1. 选择**集成请求**选项卡，然后在**集成请求设置**部分中，选择**编辑**。

1. 选择**映射模板**，然后选择**添加映射模板**。

1. 对于**内容类型**，输入 **application/json**。

1. 对于**模板正文**，输入以下模板：

   ```
   #set($inputRoot = $input.path('$'))
   {
       "stageName" : "$stageVariables.stageName"
   }
   ```
**注意**  
 在映射模板中，阶段变量必须在引号中引用（如 `"$stageVariables.stageName"` 或 `"${stageVariables.stageName}"` 中所示）。在其他位置，必须不带引号引用（如 `${stageVariables.function}` 中所示）。

1. 选择**保存**。

1. 将 API 部署到 **beta** 和 **prod** 阶段。

1. 要使用 REST API 客户端传递特定于阶段的元数据，请执行以下操作：

   1. 在**阶段**导航窗格中，选择 **beta** 阶段。在**阶段详细信息**下，选择复制图标以复制 API 的调用 URL，然后在 REST API 客户端的输入字段中输入 API 的调用 URL。在提交请求之前附加 **/lambdav1**。

      您将收到以下响应。

      ```
      "Hello, World! I'm calling from the beta stage."
      ```

   1. 在**阶段**导航窗格中，选择 **prod**。在**阶段详细信息**下，选择复制图标以复制 API 的调用 URL，然后在 REST API 客户端的输入字段中输入 API 的调用 URL。在提交请求之前附加 **/lambdav1**。

      您将收到以下响应。

      ```
      "Hello, World! I'm calling from the prod stage."
      ```

1. 要使用**测试**特征传递特定于阶段的元数据，请执行以下操作：

   1. 在**资源**导航窗格中，选择**测试**选项卡。您可能需要选择右箭头按钮以显示该选项卡。

   1. 对于 **function**，请输入 **HelloWorld**。

   1. 对于 **stageName**，请输入 **beta**。

   1. 选择**测试**。您无需将正文添加到您的 `POST` 请求。

      您将收到以下响应。

      ```
      "Hello, World! I'm calling from the beta stage."
      ```

   1. 您可以重复前面的步骤来测试 **Prod** 阶段。对于 **stageName**，请输入 **Prod**。

      您将收到以下响应。

      ```
      "Hello, World! I'm calling from the prod stage."
      ```

# API Gateway 中的 REST API 的 API Gateway 阶段变量引用
<a name="aws-api-gateway-stage-variables-reference"></a>

 在以下情况下，您可以使用 API Gateway 阶段变量。

## 参数映射表达式
<a name="stage-variables-in-parameter-mapping-expressions"></a>

阶段变量可在参数映射表达式中用于 API 方法的请求或响应标头参数，无需进行任何部分替换。在以下示例中，引用阶段变量时未使用 `$` 和封闭的 `{...}`。
+ `stageVariables.<variable_name>`

## 映射模板
<a name="stage-variables-in-mapping-templates"></a>

 阶段变量可在映射模板中的任何位置使用，如以下示例所示。
+  `{ "name" : "$stageVariables.<variable_name>"}`
+ `{ "name" : "${stageVariables.<variable_name>}"}`

## HTTP 集成 URI
<a name="stage-variables-in-integration-HTTP-uris"></a>

阶段变量可用作 HTTP 集成 URL 的一部分，如以下示例所示：
+ 不带协议的完整 URI – `http://${stageVariables.<variable_name>}`
+ 完整域 – `http://${stageVariables.<variable_name>}/resource/operation`
+ 子域 – `http://${stageVariables.<variable_name>}.example.com/resource/operation`
+ 路径 – `http://example.com/${stageVariables.<variable_name>}/bar`
+ 查询字符串 – `http://example.com/foo?q=${stageVariables.<variable_name>}` 

## AWS 集成 URI
<a name="stage-variables-in-integration-aws-uris"></a>

 阶段变量可用作 AWS URI 操作或路径组件的一部分，如以下示例所示。
+ `arn:aws:apigateway:<region>:<service>:${stageVariables.<variable_name>}`

## AWS 集成 URI（Lambda 函数）
<a name="stage-variables-in-integration-lambda-functions"></a>

 阶段变量可用于替代 Lambda 函数名称或版本/别名，如以下示例所示。
+ `arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/arn:aws:lambda:<region>:<account_id>:function:${stageVariables.<function_variable_name>}/invocations`
+ `arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/arn:aws:lambda:<region>:<account_id>:function:<function_name>:${stageVariables.<version_variable_name>}/invocations`

**注意**  
要将阶段变量用于 Lambda 函数，该函数必须与 API 位于同一账户中。阶段变量不支持跨账户 Lambda 函数。

## Amazon Cognito 用户池
<a name="stage-variables-in-integration-lambda-functions"></a>

阶段变量可用来代替 `COGNITO_USER_POOLS` 授权方的 Amazon Cognito 用户池。
+ `arn:aws:cognito-idp:<region>:<account_id>:userpool/${stageVariables.<variable_name>}`

## AWS 集成凭证
<a name="stage-variables-in-integration-aws-credentials"></a>

 阶段变量可用作 AWS 用户/角色凭证 ARN 的一部分，如以下示例所示。
+  `arn:aws:iam::<account_id>:${stageVariables.<variable_name>}` 