使用 AWS API 网关调用 AWS Lambda
Invoke AWS Lambda with AWS API Gateway
我正在将一些 scala 代码移动到 AWS Lambda,我打算通过 AWS API 网关公开它,但我一直在努力让整个事情在我有一个参数后立即运行.
我的(非常简单的)代码如下所示:
class HelloService {
def hello(name: String) = {
"hello there, " + name
}
}
我将构建的 jar 上传到 Lambda 并通过创建测试事件在 AWS 控制台中对其进行了测试。正如预期的那样,它 returns 是正确的响应。
但是,我希望此 Lambda 由 API 网关调用。我使用了 Lambda 代理集成,还定义了我自己的 Body 映射模板。我似乎无法让它工作,而且我不断得到:
{
"message": "Internal server error"
}
有日志:
Execution log for request test-request Mon Jul 03 16:23:21 UTC 2017 :
Starting execution for request: test-invoke-request Mon Jul 03
16:23:21 UTC 2017 : HTTP Method: GET, Resource Path: /car/aaa Mon Jul
03 16:23:21 UTC 2017 : Method request path: {carReg=aaa} Mon Jul 03
16:23:21 UTC 2017 : Method request query string: {} Mon Jul 03
16:23:21 UTC 2017 : Method request headers: {} Mon Jul 03 16:23:21 UTC
2017 : Method request body before transformations: Mon Jul 03
16:23:21 UTC 2017 : Endpoint request URI:
https://lambda.eu-west-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-west-1:879461422967:function:getCarData/invocations
Mon Jul 03 16:23:21 UTC 2017 : Endpoint request headers:
{x-amzn-lambda-integration-tag=test-request,
Authorization=****************************************************************************************************************************************************************************************************************************************************************************************************************************************f8c749, X-Amz-Date=20170703T162321Z, x-amzn-apigateway-api-id=9dwaaf2mdg,
X-Amz-Source-Arn=arn:aws:execute-api:eu-west-1:879461422967:9dwaaf2mdg/null/GET/car/{carReg+},
Accept=application/json, User-Agent=AmazonAPIGateway_9dwaaf2mdg,
X-Amz-Security-Token=FQoDYXdzENn//////////wEaDMO73KD0CHVmggvYvSK3A8H1fpDgYiNK3HDD3ESe1aKYbv1HlGSQ85at3gRGA3kunmxVCxWbXNqR4ojBCn4hvBzdv1/iWD9xRzZQEtnQeDoO9NTuiBdYaXKgwjGozPKF/46X71f0sCt/Mm9i8EDtt3igEezJIhAF3OvYcdv2NBF3L0mRMMQKp4Vy+aC0mKu4ggadyLe+KYvmch8/AiZPlrxC1AtqwNGyWpSe1JqxeEXQGXIA5JsfwGpnpAB5IUec2r3Bd09zUFk/DCC80l9d4BLnhYAUn7xzrKYzisSEQitmhnTR3HijEYE6AJzJjFR+z2PqqVKvtgKQ
[TRUNCATED] Mon Jul 03 16:23:21 UTC 2017 : Endpoint request body after
transformations: { "message" : "foo" } Mon Jul 03 16:23:21 UTC 2017
: Endpoint response body before transformations: {"errorMessage":"An
error occurred during JSON
parsing","errorType":"java.lang.RuntimeException","stackTrace":[],"cause":{"errorMessage":"com.fasterxml.jackson.databind.JsonMappingException:
Can not deserialize instance of java.lang.String out of START_OBJECT
token\n at [Source:
lambdainternal.util.NativeMemoryAsInputStream@e720b71; line: 1,
column:
1]","errorType":"java.io.UncheckedIOException","stackTrace":[],"cause":{"errorMessage":"Can
not deserialize instance of java.lang.String out of START_OBJECT
token\n at [Source:
lambdainternal.util.NativeMemoryAsInputStream@e720b71; line: 1,
column:
1]","errorType":"com.fasterxml.jackson.databind.JsonMappingException","stackTrace":["com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)","com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:857)","com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java
[TRUNCATED] Mon Jul 03 16:23:21 UTC 2017 : Endpoint response headers:
{x-amzn-Remapped-Content-Length=0,
x-amzn-RequestId=ede9aaed-600b-11e7-834e-47baf0a4e23f,
Connection=keep-alive, Content-Length=1252,
X-Amz-Function-Error=Unhandled, Date=Mon, 03 Jul 2017 16:23:20 GMT,
X-Amzn-Trace-Id=root=1-595a6f79-c065d6038ba3209743378112;sampled=0,
Content-Type=application/json} Mon Jul 03 16:23:21 UTC 2017 :
Execution failed due to configuration error: Output mapping refers to
an invalid method response: 200 Mon Jul 03 16:23:21 UTC 2017 : Method
completed with status: 500
我的 ARN 路径中有一个空值,但我想那是因为我没有设置身份验证,这正是此时的目的。我认为这不是错误的原因。
除此之外,我尝试将 body 的 Content-Type 定义为 application/json 和 text/plain。 None 似乎有效,即使使用 text/plain,AWS 似乎也在期待 json。无论如何,我希望字符串有效 json 。
我做错了什么?我应该在 Body 映射模板中输入的完整表达式是什么?我的模型中的模式定义应该是什么样子的?我似乎无法为纯文本定义合适的模型。
我确定这真的很简单,我只是遗漏了一些东西...
使用 Lambda 代理,您必须 return 字符串化 JSON。
使用 Lambda,您可以从您的 Lambda return JSON 然后让您的 API 网关正文映射模板为您将其字符串化。
有关其他上下文和示例,请参阅 this page from Serverless docs。
您发回服务器的响应取决于您是否使用 Lambda 代理集成。在 API 网关端使用代理集成更容易设置,但您的 Lambda 需要做更多的工作,因为网关将向您发送一堆内容并要求在响应中使用特定格式。对于代理集成,响应格式需要如下所示:
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}
如果您不使用代理集成,则需要在 API 网关集成中为您的参数设置正文映射,以便将 api 参数与 lambda 参数相匹配.在此处接受的答案中有一个很好的解释:
我正在将一些 scala 代码移动到 AWS Lambda,我打算通过 AWS API 网关公开它,但我一直在努力让整个事情在我有一个参数后立即运行.
我的(非常简单的)代码如下所示:
class HelloService {
def hello(name: String) = {
"hello there, " + name
}
}
我将构建的 jar 上传到 Lambda 并通过创建测试事件在 AWS 控制台中对其进行了测试。正如预期的那样,它 returns 是正确的响应。
但是,我希望此 Lambda 由 API 网关调用。我使用了 Lambda 代理集成,还定义了我自己的 Body 映射模板。我似乎无法让它工作,而且我不断得到:
{
"message": "Internal server error"
}
有日志:
Execution log for request test-request Mon Jul 03 16:23:21 UTC 2017 : Starting execution for request: test-invoke-request Mon Jul 03 16:23:21 UTC 2017 : HTTP Method: GET, Resource Path: /car/aaa Mon Jul 03 16:23:21 UTC 2017 : Method request path: {carReg=aaa} Mon Jul 03 16:23:21 UTC 2017 : Method request query string: {} Mon Jul 03 16:23:21 UTC 2017 : Method request headers: {} Mon Jul 03 16:23:21 UTC 2017 : Method request body before transformations: Mon Jul 03 16:23:21 UTC 2017 : Endpoint request URI: https://lambda.eu-west-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-west-1:879461422967:function:getCarData/invocations Mon Jul 03 16:23:21 UTC 2017 : Endpoint request headers: {x-amzn-lambda-integration-tag=test-request, Authorization=****************************************************************************************************************************************************************************************************************************************************************************************************************************************f8c749, X-Amz-Date=20170703T162321Z, x-amzn-apigateway-api-id=9dwaaf2mdg, X-Amz-Source-Arn=arn:aws:execute-api:eu-west-1:879461422967:9dwaaf2mdg/null/GET/car/{carReg+}, Accept=application/json, User-Agent=AmazonAPIGateway_9dwaaf2mdg, X-Amz-Security-Token=FQoDYXdzENn//////////wEaDMO73KD0CHVmggvYvSK3A8H1fpDgYiNK3HDD3ESe1aKYbv1HlGSQ85at3gRGA3kunmxVCxWbXNqR4ojBCn4hvBzdv1/iWD9xRzZQEtnQeDoO9NTuiBdYaXKgwjGozPKF/46X71f0sCt/Mm9i8EDtt3igEezJIhAF3OvYcdv2NBF3L0mRMMQKp4Vy+aC0mKu4ggadyLe+KYvmch8/AiZPlrxC1AtqwNGyWpSe1JqxeEXQGXIA5JsfwGpnpAB5IUec2r3Bd09zUFk/DCC80l9d4BLnhYAUn7xzrKYzisSEQitmhnTR3HijEYE6AJzJjFR+z2PqqVKvtgKQ [TRUNCATED] Mon Jul 03 16:23:21 UTC 2017 : Endpoint request body after transformations: { "message" : "foo" } Mon Jul 03 16:23:21 UTC 2017 : Endpoint response body before transformations: {"errorMessage":"An error occurred during JSON parsing","errorType":"java.lang.RuntimeException","stackTrace":[],"cause":{"errorMessage":"com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@e720b71; line: 1, column: 1]","errorType":"java.io.UncheckedIOException","stackTrace":[],"cause":{"errorMessage":"Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@e720b71; line: 1, column: 1]","errorType":"com.fasterxml.jackson.databind.JsonMappingException","stackTrace":["com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)","com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:857)","com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java [TRUNCATED] Mon Jul 03 16:23:21 UTC 2017 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=ede9aaed-600b-11e7-834e-47baf0a4e23f, Connection=keep-alive, Content-Length=1252, X-Amz-Function-Error=Unhandled, Date=Mon, 03 Jul 2017 16:23:20 GMT, X-Amzn-Trace-Id=root=1-595a6f79-c065d6038ba3209743378112;sampled=0, Content-Type=application/json} Mon Jul 03 16:23:21 UTC 2017 : Execution failed due to configuration error: Output mapping refers to an invalid method response: 200 Mon Jul 03 16:23:21 UTC 2017 : Method completed with status: 500
我的 ARN 路径中有一个空值,但我想那是因为我没有设置身份验证,这正是此时的目的。我认为这不是错误的原因。
除此之外,我尝试将 body 的 Content-Type 定义为 application/json 和 text/plain。 None 似乎有效,即使使用 text/plain,AWS 似乎也在期待 json。无论如何,我希望字符串有效 json 。
我做错了什么?我应该在 Body 映射模板中输入的完整表达式是什么?我的模型中的模式定义应该是什么样子的?我似乎无法为纯文本定义合适的模型。
我确定这真的很简单,我只是遗漏了一些东西...
使用 Lambda 代理,您必须 return 字符串化 JSON。
使用 Lambda,您可以从您的 Lambda return JSON 然后让您的 API 网关正文映射模板为您将其字符串化。
有关其他上下文和示例,请参阅 this page from Serverless docs。
您发回服务器的响应取决于您是否使用 Lambda 代理集成。在 API 网关端使用代理集成更容易设置,但您的 Lambda 需要做更多的工作,因为网关将向您发送一堆内容并要求在响应中使用特定格式。对于代理集成,响应格式需要如下所示:
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}
如果您不使用代理集成,则需要在 API 网关集成中为您的参数设置正文映射,以便将 api 参数与 lambda 参数相匹配.在此处接受的答案中有一个很好的解释: