使用代理集成通过 API Gateway 触发 AWS Lambda

Posted

技术标签:

【中文标题】使用代理集成通过 API Gateway 触发 AWS Lambda【英文标题】:Trigger AWS Lambda through API Gateway using Proxy Integration 【发布时间】:2018-05-04 22:13:03 【问题描述】:

我刚刚开始使用 AWS,并在 AWS Lambda 中制作了一个基本计算器,如下所示:

import json

def lambda_handler(event, context):
op1 = event.get('op1',0)
op2 = event.get('op2',0)
operator = event.get('op', None)
if op1 == 0 or op2 == 0 or operator == None:
    result = 'Please enter valid input data'
    ret_code = 219
else:
    if operator in 'add', 'plus', '+':
        result = op1 + op2
        ret_code = 278
    elif operator in 'subtract', 'minus', '-':
        result = op1 - op2
        ret_code = 278
    elif operator in 'multiply', '*':
        result = op1 * op2
        ret_code = 278
    elif operator in 'divide', '/':
        result = op1 / op2
        ret_code = 278
    else:
        result = 'Please enter valid operator'
        ret_code = 219
return 
    'isBase64Encoded': False,
    'statusCode': ret_code,
    'headers': 'Content-Type': 'application/json',
    'body': json.dumps(result)

当我使用以下方法测试 Lambda 时,此函数工作正常


"op1": 7,
"op2": 9,
"op": "divide"

然后我在 Amazon API Gateway 中创建了一个 API,并将其配置为使用 Lambda 代理集成,如 API Setup 所示。

但是,现在当我尝试通过 PUT 或 POST 通过与以前相同的输入数据触发 AWS Lambda 时,我收到 219 错误,这意味着数据没有被传递到 Lambda 事件中,而是 Lambda 是使用默认零,给出错误。我从 API Gateway 得到的响应如下:

Execution log for request test-request
Tue Nov 21 12:19:34 UTC 2017 : Starting execution for request: test-invoke-request
Tue Nov 21 12:19:34 UTC 2017 : HTTP Method: PUT, Resource Path: /
Tue Nov 21 12:19:34 UTC 2017 : Method request path: 
Tue Nov 21 12:19:34 UTC 2017 : Method request query string: 
Tue Nov 21 12:19:34 UTC 2017 : Method request headers: 
Tue Nov 21 12:19:34 UTC 2017 : Method request body before transformations: 
"op1": 7,
"op2": 9,
"op": "divide"

Tue Nov 21 12:19:34 UTC 2017 : Endpoint request URI: https://lambda.eu-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-west-2:*:function:newCalc/invocations
Tue Nov 21 12:19:34 UTC 2017 : Endpoint request headers: x-amzn-lambda-integration-tag=test-request, Authorization=*, X-Amz-Date=20171121T121934Z, x-amzn-apigateway-api-id=*, X-Amz-Source-Arn=arn:aws:execute-api:eu-west-2:*:wrsio8dvp3/null/PUT/proxy+, Accept=application/json, User-Agent=AmazonAPIGateway_*, X-Amz-Security-Token=*
Tue Nov 21 12:19:34 UTC 2017 : Endpoint request body after transformations: "resource":"/proxy+","path":"/","httpMethod":"PUT","headers":null,"queryStringParameters":null,"pathParameters":null,"stageVariables":null,"requestContext":"path":"/proxy+","accountId":"*","resourceId":"fsamcn","stage":"test-invoke-stage","requestId":"test-invoke-request","identity":"cognitoIdentityPoolId":null,"accountId":"*","cognitoIdentityId":null,"caller":"*","apiKey":"test-invoke-api-key","sourceIp":"test-invoke-source-ip","accessKey":"*","cognitoAuthenticationType":null,"cognitoAuthenticationProvider":null,"userArn":"arn:aws:iam::*:user/*","userAgent":"Apache-HttpClient/4.5.x (Java/1.8.0_144)","user":"*","resourcePath":"/proxy+","httpMethod":"PUT","apiId":"wrsio8dvp3","body":"\n  \"op1\": 7,\n  \"op2\": 9,\n  \"op\": \"divide\"\n","isBase64Encoded":false
Tue Nov 21 12:19:34 UTC 2017 : Sending request to https://lambda.eu-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-west-2:*:function:newCalc/invocations
Tue Nov 21 12:19:34 UTC 2017 : Received response. Integration latency: 287 ms
Tue Nov 21 12:19:34 UTC 2017 : Endpoint response body before transformations: "isBase64Encoded": false, "statusCode": 219, "headers": "Content-Type": "application/json", "body": "\"Please enter valid input data\""
Tue Nov 21 12:19:34 UTC 2017 : Endpoint response headers: x-amzn-Remapped-Content-Length=0, Connection=keep-alive, x-amzn-RequestId=3befcbd6-ceb6-11e7-a4dd-c3db02aba4a2, Content-Length=139, Date=Tue, 21 Nov 2017 12:19:34 GMT, X-Amzn-Trace-Id=root=1-5a1419d6-106413cfbf4bf985d840894f;sampled=0, Content-Type=application/json
Tue Nov 21 12:19:34 UTC 2017 : Method response body after transformations: "Please enter valid input data"
Tue Nov 21 12:19:34 UTC 2017 : Method response headers: X-Amzn-Trace-Id=sampled=0;root=1-5a1419d6-106413cfbf4bf985d840894f, Content-Type=application/json
Tue Nov 21 12:19:34 UTC 2017 : Successfully completed execution
Tue Nov 21 12:19:34 UTC 2017 : Method completed with status: 219

那么,您能否帮我弄清楚我做错了什么 - 以及如何正确格式化我的请求正文以便能够触发 Lambda 函数。

【问题讨论】:

【参考方案1】:

您面临的问题来自 api 网关的代理集成。如果您选中此项,则为您的 lambda 提供的输入结构不再是提供给您 PUT 操作的普通负载。

您的事件参数实际上由以下结构组成(在您的日志中,Endpoint request body after transformations 行)


    "resource": "/proxy+",
    "path": "/",
    "httpMethod": "PUT",
    "headers": null,
    "queryStringParameters": null,
    "pathParameters": null,
    ....
    "body": "\n  \"op1\": 7,\n  \"op2\": 9,\n  \"op\": \"divide\"\n",
    "isBase64Encoded": false

因此,要访问您的原始事件,您必须解码 event.body 元素。

【讨论】:

将代码更新为首先使用 payload = json.loads(event.get('body')) 将 event.body 作为 dict 读取,然后通过 op1 = payload['op1'] 读取单个元素

以上是关于使用代理集成通过 API Gateway 触发 AWS Lambda的主要内容,如果未能解决你的问题,请参考以下文章

使用代理通过 AWS API Gateway 的 Lambda 错误

不使用 API Gateway 代理集成无法调用后端服务

API Gateway Lambda 端点代理与非代理集成

如何允许 API Gateway 代理与 Cognito Authorizer 集成以进行 POST 请求?

使用 HTTP 代理访问 AWS API Gateway 中的标头?

AWS API Gateway 仅在使用 SAM 时支持 CORS for OPTIONS(没有 Lambda 代理集成)