Amazon API Gateway
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 Amazon AWS 入门

使用 Lambda 代理集成构建 API Gateway API

在本部分中,我们将演示如何通过 API Gateway 控制台使用 Lambda 集成创建并测试 API。我们将演示 Lambda 后端如何解析原始请求并根据传入请求数据实现应用程序逻辑。有关 API Gateway 代理集成的更多信息,请参阅设置具有代理资源的代理集成

首先,我们使用 AWS Lambda 控制台创建以下名为 GetStartedLambdaProxyIntegration 的 Node.js 函数作为后端。然后,我们将在 API Gateway 控制台中,通过 Lambda 代理集成 (使用 GetStartedLambdaProxyIntegration 函数) 使用 代理资源 创建一个 API。最后,我们将演示如何测试 API。

使用 Lambda 代理集成为 API 创建 Lambda 函数

我们将创建一个 Lambda 函数,该函数会将问候语作为以下格式的 JSON 对象返回给调用方:

{ "greeting": "Good {time}, {name} of {city}.[ Happy {day}]" }

在此示例中,{time} 可以是 morningafternoonday{name} 可以是 you 或用户指定的用户名;{city} 可以是 World 或用户提供的城市名称;{day} 可以为 null、空或星期几。如果 {day} 为 null 或为空,将不显示 Happy {day} 部分。Lambda 函数非常灵活,客户端可以采用请求标头、路径变量、查询字符串参数和正文的任意组合来指定输入。

为了显示 API Gateway 传递给后端的内容,我们还将 event 对象包含到 Lambda 函数的输出中。最后,我们创建了一个 response 对象,来说明 Lambda 代理集成所需的基本输出格式。

可在 Node.js、Python、Java 和 C # 中编写 Lambda 函数。在本教程中,我们将演示采用 Node.js 和 Java 的代码段。您可以将 Node.js 实现扩展至 Python 函数或将 Java 实现扩展至 C # 函数。以下主题中提供了相关的操作说明。

与 Lambda 代理集成的 API 的 Node.js 函数

Node.js 中的以下 Lambda 函数是一个“Hello,World!”应用程序. 此函数展示了如何解析含有客户端发送给 API Gateway 代理资源的请求的输入 event 参数。该资源与使用 Lambda 代理集成的函数相集成。此外,此函数还演示了如何格式化 Lambda 函数的输出,以便 API Gateway 将结果作为 HTTP 响应返回。有关此类 Lambda 函数必须遵循的输入和输出格式的更多信息,请参阅 用于代理集成的 Lambda 函数的输入格式 用于代理集成的 Lambda 函数的输出格式

'use strict'; console.log('Loading hello world function'); exports.handler = function(event, context, callback) { let name = "you"; let city = 'World'; let time = 'day'; let day = ''; let responseCode = 200; console.log("request: " + JSON.stringify(event)); // This is a simple illustration of app-specific logic to return the response. // Although only 'event.queryStringParameters' are used here, other request data, // such as 'event.headers', 'event.pathParameters', 'event.body', 'event.stageVariables', // and 'event.requestContext' can be used to determine what response to return. // if (event.queryStringParameters !== null && event.queryStringParameters !== undefined) { if (event.queryStringParameters.name !== undefined && event.queryStringParameters.name !== null && event.queryStringParameters.name !== "") { console.log("Received name: " + event.queryStringParameters.name); name = event.queryStringParameters.name; } } if (event.pathParameters !== null && event.pathParameters !== undefined) { if (event.pathParameters.proxy !== undefined && event.pathParameters.proxy !== null && event.pathParameters.proxy !== "") { console.log("Received proxy: " + event.pathParameters.proxy); city = event.pathParameters.proxy; } } if (event.headers !== null && event.headers !== undefined) { if (event.headers['day'] !== undefined && event.headers['day'] !== null && event.headers['day'] !== "") { console.log("Received day: " + event.headers.day); day = event.headers.day; } } if (event.body !== null && event.body !== undefined) { let body = JSON.parse(event.body) if (body.time) time = body.time; } let greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. '; if (day) greeting += 'Happy ' + day + '!'; var responseBody = { message: greeting, input: event }; // The output from a Lambda proxy integration must be // of the following JSON object. The 'headers' property // is for custom response headers in addition to standard // ones. The 'body' property must be a JSON string. For // base64-encoded payload, you must also set the 'isBase64Encoded' // property to 'true'. var response = { statusCode: responseCode, headers: { "x-custom-header" : "my custom header value" }, body: JSON.stringify(responseBody) }; console.log("response: " + JSON.stringify(response)) callback(null, response); };

对于 API Gateway 代理集成,event 的输入参数包含一个被 API Gateway 封送为 JSON 对象的 API 请求。此输入可以包含请求的 HTTP 方法 (httpMethod)、路径 (pathpathParameters)、查询参数 (queryStringParameters)、标头 (headers) 和适用的负载 (body)。输入还可以包含上下文 (requestContext) 和阶段变量 (stageVariables)。

此示例 Lambda 函数解析 event 参数,用于检索 name 的查询字符串参数、proxy 路径参数、day 标头值以及负载的 time 属性。

然后,函数会在 responseBody 对象的 message 属性中向指定用户返回问候语。为了显示由 API Gateway 封送的传入请求的详细信息,该函数还会将传入 event 对象作为响应正文的 input 属性返回。

最后,在退出时,该函数会返回一个 JSON 对象,其中包含所需的 statusCode 和任何适用的 headersbody,以便 API Gateway 将其作为 HTTP 响应返回到客户端。

与 Lambda 代理集成的 API 的 Python 函数

按照使用 Python 编写 Lambda 函数中的讨论,创建 Python Lambda 函数处理程序,同时扩展前面 Node.js Lambda 函数中显示的编程流。

与 Lambda 代理集成的 API 的 C# 函数

按照使用 C# 编写 Lambda 函数中的说明,创建 C# Lambda 函数处理程序,同时扩展下面 Java Lambda 函数中显示的编程流。

与 Lambda 代理集成的 API 的 Java 函数

Java 中的以下 Lambda 函数是一个“Hello,World!”应用程序,与其 Node.js 的对应情况类似。此函数展示了如何解析作为 InputStream 对象传递的输入事件,以及如何解析包含客户端发给 API Gateway 代理资源的请求的输入事件。该资源与使用 Lambda 代理集成的函数相集成。它还说明了如何解析 context 对象以获取 LambdaLogger。该示例还演示了如何格式化 Java 中 Lambda 函数的输出,以便 API Gateway 将 OutputStream 对象中的结果作为 HTTP 响应返回。有关 Lambda 代理集成输入和输出格式的更多信息,请参阅 用于代理集成的 Lambda 函数的输入格式 用于代理集成的 Lambda 函数的输出格式

package examples; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.BufferedReader; import java.io.Writer; import com.amazonaws.services.lambda.runtime.RequestStreamHandler; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import org.json.simple.JSONObject; import org.json.simple.JSONArray; import org.json.simple.parser.ParseException; import org.json.simple.parser.JSONParser; public class ProxyWithStream implements RequestStreamHandler { JSONParser parser = new JSONParser(); public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { LambdaLogger logger = context.getLogger(); logger.log("Loading Java Lambda handler of ProxyWithStream"); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); JSONObject responseJson = new JSONObject(); String name = "you"; String city = "World"; String time = "day"; String day = null; String responseCode = "200"; try { JSONObject event = (JSONObject)parser.parse(reader); if (event.get("queryStringParameters") != null) { JSONObject qps = (JSONObject)event.get("queryStringParameters"); if ( qps.get("name") != null) { name = (String)qps.get("name"); } } if (event.get("pathParameters") != null) { JSONObject pps = (JSONObject)event.get("pathParameters"); if ( pps.get("proxy") != null) { city = (String)pps.get("proxy"); } } if (event.get("headers") != null) { JSONObject hps = (JSONObject)event.get("headers"); if ( hps.get("day") != null) { day = (String)hps.get("day"); } } if (event.get("body") != null) { JSONObject body = (JSONObject)parser.parse((String)event.get("body")); if ( body.get("time") != null) { time = (String)body.get("time"); } } String greeting = "Good " + time + ", " + name + " of " + city + ". "; if (day!=null && day != "") greeting += "Happy " + day + "!"; JSONObject responseBody = new JSONObject(); responseBody.put("input", event.toJSONString()); responseBody.put("message", greeting); JSONObject headerJson = new JSONObject(); headerJson.put("x-custom-header", "my custom header value"); responseJson.put("statusCode", responseCode); responseJson.put("headers", headerJson); responseJson.put("body", responseBody.toString()); } catch(ParseException pex) { responseJson.put("statusCode", "400"); responseJson.put("exception", pex); } logger.log(responseJson.toJSONString()); OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8"); writer.write(responseJson.toJSONString()); writer.close(); } }

对于 API Gateway 中的代理集成,输入流将包含由 API Gateway 序列化为 JSON 字符串的 API 请求。输入数据可能包含该请求的 HTTP 方法 (httpMethod)、路径 (pathpathParameters)、查询参数 (queryStringParameters),标头 (headers)、适用的有效负载 (body)、上下文 (requestContext) 和阶段变量 (stageVariables)。

此示例 Lambda 函数解析 inputStream 参数,用于检索 name 的查询字符串参数、proxy 路径参数、day 标头值以及负载的 time 属性。对于日志记录,它会从传入的 context 对象中检索 LambdaLogger 对象。

然后,函数会在 responseBody 对象的 message 属性中向指定用户返回问候语。为了显示由 API Gateway 封送的传入请求的详细信息,该函数还将返回响应主体中的输入数据 (event)。

最后,在退出时,此函数会返回一个 JSON 字符串,其中包含所需的 statusCode 和任何适用的 headersbody,以便 API Gateway 将其作为 HTTP 响应返回到客户端。

要在 Lambda 控制台中创建此函数,您必须先创建一个部署程序包,然后将该程序包上传到 Lambda。有关更多信息,请参阅 AWS Lambda 开发人员指南 中的创建部署程序包

使用 Lambda 代理集成为 API 创建后端

以下过程介绍如何使用 Lambda 控制台在 API Gateway 中创建 Lambda 函数。

在 Lambda 控制台中使用 代理资源 为 API 创建 Lambda 函数

  1. 通过 https://console.amazonaws.cn/lambda 登录 Lambda 控制台。

  2. 在右上角,为 Lambda 函数选择一个可用区域。

  3. 从主导航窗格中选择 Functions。如果未显示导航窗格,您可能需要在左上角选择导航菜单。

  4. 选择 Create function。然后选择 Author from scratchBlueprints。在本示例中,我们从头创建函数。

  5. Author from scratch 下,执行以下操作:

    1. Name 输入字段中,键入函数名称。

    2. Runtime 下拉列表中,选择受支持的运行时。在本示例中,我们使用 Node.js 4.3

    3. Role 下拉列表中,选择 Choose an existing roleCreate new role from template(s)Create a custom role。然后,按照此选择随后的说明操作。

    4. 选择 Create function 以继续。

      在本示例中,我们将跳过 Designer 部分,进入下一个 Function code 部分。

  6. 对于 Node 或 Python 运行时,除了从本地驱动器或从 Amazon S3 上传压缩的代码文件外,您还可以使用内联代码编辑器创建或编辑 lambda 函数。对于 Java 或 C# 运行时,您必须从本地驱动器或从 Amazon S3 上传压缩的代码文件。在任何情况下都请使用指定运行时的代码示例,请遵照 使用 Lambda 代理集成为 API 创建 Lambda 函数 此处说明。

  7. 选择 Save 以完成 Lambda 函数的创建。

  8. (可选) 但是强烈建议,选择 Test 并配置测试事件以采用必要的 Lambda 代理集成请求输入

注意

请注意您创建 Lambda 函数时所在的区域,您在为该函数创建 API 时需要用到它。

使用 Lambda 代理集成创建 API

现在,让我们通过 API Gateway 控制台使用 代理资源 为 Lambda 函数创建 API。

使用 代理资源 为 Lambda 函数构建 API

  1. 通过 https://console.amazonaws.cn/apigateway 登录 API Gateway 控制台。

  2. 要创建 API,请选择 Create new API (用于创建第一个 API) 或 Create API (用于创建任何后续 API)。接下来执行以下操作:

    1. 选择 New API

    2. API Name 中键入名称。

    3. 还可选择在 Description 中添加简短描述。

    4. 选择 Create API

    在本教程中,请使用 LambdaSimpleProxy 作为 API 名称。

  3. 要创建子资源,请选择 Resources 树下的父资源项目,然后从 Actions 下拉菜单中选择 Create Resource。接下来在 New Child Resource 窗格中执行以下操作。

    1. 选择 Configure as proxy resource 选项以创建代理资源。否则,将其保持未选中状态。

    2. Resource Name* 输入文本字段中键入一个名称。

    3. Resource Path* 输入文本字段中键入一个新名称或使用默认名称。

    4. 选择 Create Resource

    5. 如果需要,则选择 Enable API Gateway CORS

    在本教程中,请使用根资源 (/) 作为父资源。选择 Configure as proxy resource。对于 Resource Name,使用默认值 proxy。对于 Resource Path,使用 /{proxy+}。取消选择 Enable API Gateway CORS

  4. 要设置与 Lambda 后端集成的 ANY 方法,请执行以下操作:

    1. 选择刚刚创建的资源,从 Actions 下拉菜单中选择 Create Method

    2. 从 HTTP 方法下拉列表中选择 ANY,然后选择复选标记图标以保存选择。

    3. Integration type 选择 Lambda Function Proxy

    4. Lambda Region 中选择一个区域。

    5. Lambda Function 中键入 Lambda 函数的名称。

    6. 选择 Save

    7. 在出现 Add Permission to Lambda Function 提示时,选择 OK

    在本教程中,对于 Lambda Function,使用之前创建的 GetStartedLambdaProxyIntegration

对于 Lambda 刚刚创建的 代理资源 API,API Gateway 会将原始请求从客户端转发到后端以供 Lambda 函数处理。该请求包含请求方法、路径、查询字符串和标头参数、任何负载、上下文和阶段变量。下一过程将介绍如何对其进行测试。

使用 Lambda 代理集成测试 API

以下过程将介绍如何测试代理集成。

通过 代理资源 调用 GetStartedLambdaProxyIntegration Lambda 函数。

  • 要使用浏览器对 API 的特定资源调用 GET 方法,请执行以下操作。

    1. 从您创建的 API 的 Actions 下拉菜单中选择 Deploy API (如果您尚未这么做)。按照说明将 API 部署到特定阶段。请注意显示在生成的 Stage Editor 页面上的 Invoke URL。这是 API 的基本 URL。

    2. 要在特定资源上提交 GET 请求,请将资源路径 (包括可能的查询字符串表达式) 附加到上一步中获取的 Invoke URL 值,将完整 URL 复制到浏览器的地址栏中,然后按 Enter。

    在本教程中,将 API 部署到 test 阶段并记录 API 的基本 URL;例如,https://wt6mne2s9k.execute-api.us-west-2.amazonaws.com/test

    可通过若干种方法来测试已部署的 API。对于仅使用 URL 路径变量或查询字符串参数的 GET 请求,您可以在浏览器中键入 API 资源的 URL。对于其他方法,您必须使用更高级的 REST API 测试实用程序,如 POSTMANcURL

    使用 cURL 测试已部署的 API

    1. 在连接到 Internet 的本地计算机上打开终端窗口。

    2. 测试 POST /Seattle?time=evening

      复制以下 cURL 命令并将其粘贴到终端窗口中。

      curl -v -X POST \ 'https://r275xc9bmd.execute-api.us-west-2.amazonaws.com/test/Seattle?time=evening' \ -H 'content-type: application/json' \ -H 'day: Thursday' \ -H 'x-amz-docs-region: us-west-2' \ -d '{ "callerName": "John" }'

      您应获得一个包含以下负载的成功响应:

      { "message": "Good day, John of Seattle. Happy Friday!", "input": { "resource": "/{proxy+}", "path": "/Seattle", "httpMethod": "POST", "headers": { "day": "Friday" }, "queryStringParameters": { "time": "morning" }, "pathParameters": { "proxy": "Seattle" }, "stageVariables": null, "requestContext": { "path": "/{proxy+}", "accountId": "123456789012", "resourceId": "nl9h80", "stage": "test-invoke-stage", "requestId": "test-invoke-request", "identity": { "cognitoIdentityPoolId": null, "accountId": "123456789012", "cognitoIdentityId": null, "caller": "AIDXXX...XXVJZG", "apiKey": "test-invoke-api-key", "sourceIp": "test-invoke-source-ip", "accessKey": "ASIXXX...XXDQ5A", "cognitoAuthenticationType": null, "cognitoAuthenticationProvider": null, "userArn": "arn:aws:iam::123456789012:user/kdeding", "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_131)", "user": "AIDXXX...XXVJZG" }, "resourcePath": "/{proxy+}", "httpMethod": "POST", "apiId": "r275xc9bmd" }, "body": "{ \"callerName\": \"John\" }", "isBase64Encoded": false } }

      如果您在之前的方法请求中将 POST 更改为 PUT,则会获得相同的响应。

    3. 测试 GET /Boston?time=morning

      复制以下 cURL 命令并将其粘贴到终端窗口中。

      curl -X GET \ 'https://r275xc9bmd.execute-api.us-west-2.amazonaws.com/test/Seattle?time=evening' \ -H 'content-type: application/json' \ -H 'day: Thursday' \ -H 'x-amz-docs-region: us-west-2'

      您会收到 200 OK Request 响应,与之前的 POST 请求的结果类似,区别在于 GET 请求没有任何负载。因此,body 参数将为 null

    注意

    requestContext 是键值对的映射,与 $context 变量相对应。其结果与 API 相关。API Gateway 可能会向映射添加新键。有关更多信息,请参阅 用于代理集成的 Lambda 函数的输入格式