首页 文章

通过API网关在aws Lambda中获取json主体

提问于
浏览
37

我遇到了POST请求和JSON数据的问题 . 我的api使用了'Use Lambda Proxy integration',甚至当我测试代理发送一个内容类型的Application / json和一些json在体内,例如 {"foo":"bar"} 我无法访问该对象而不先解析它

例如

var json = JSON.parse(event.body);
  console.log(json.foo);

现在我知道这并没有看到其他一些例子,而事实并非如此 . 看到这里https://github.com/pinzler/fb-messenger-bot-aws-lambda/blob/master/index.js

我是否需要向API网关添加任何内容才能正确处理? 'post method request'部分中的'request body'步骤具有针对请求主体的内容类型application / json设置 .

据我所知,上面例子的自述文件似乎没有使用代理集成,所以我不确定我应该在这里做什么

3 回答

  • 13

    您可以在API网关中配置两种不同的Lambda集成,例如Lambda集成和Lambda代理集成 . 对于 Lambda integration ,您可以在不需要解析正文的有效负载中自定义要传递给Lambda的内容,但是当您在API网关中使用 Lambda Proxy integration 时,API网关会将所有内容代理到有效负载中的Lambda,如下所示,

    {
        "message": "Hello me!",
        "input": {
            "path": "/test/hello",
            "headers": {
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
                "Accept-Encoding": "gzip, deflate, lzma, sdch, br",
                "Accept-Language": "en-US,en;q=0.8",
                "CloudFront-Forwarded-Proto": "https",
                "CloudFront-Is-Desktop-Viewer": "true",
                "CloudFront-Is-Mobile-Viewer": "false",
                "CloudFront-Is-SmartTV-Viewer": "false",
                "CloudFront-Is-Tablet-Viewer": "false",
                "CloudFront-Viewer-Country": "US",
                "Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com",
                "Upgrade-Insecure-Requests": "1",
                "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
                "Via": "1.1 fb7cca60f0ecd82ce07790c9c5eef16c.cloudfront.net (CloudFront)",
                "X-Amz-Cf-Id": "nBsWBOrSHMgnaROZJK1wGCZ9PcRcSpq_oSXZNQwQ10OTZL4cimZo3g==",
                "X-Forwarded-For": "192.168.100.1, 192.168.1.1",
                "X-Forwarded-Port": "443",
                "X-Forwarded-Proto": "https"
            },
            "pathParameters": {"proxy": "hello"},
            "requestContext": {
                "accountId": "123456789012",
                "resourceId": "us4z18",
                "stage": "test",
                "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9",
                "identity": {
                    "cognitoIdentityPoolId": "",
                    "accountId": "",
                    "cognitoIdentityId": "",
                    "caller": "",
                    "apiKey": "",
                    "sourceIp": "192.168.100.1",
                    "cognitoAuthenticationType": "",
                    "cognitoAuthenticationProvider": "",
                    "userArn": "",
                    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
                    "user": ""
                },
                "resourcePath": "/{proxy+}",
                "httpMethod": "GET",
                "apiId": "wt6mne2s9k"
            },
            "resource": "/{proxy+}",
            "httpMethod": "GET",
            "queryStringParameters": {"name": "me"},
            "stageVariables": {"stageVarName": "stageVarValue"},
            "body": "{\"foo\":\"bar\"}",
            "isBase64Encoded": false
        }
    }
    

    对于您正在引用的示例,它不是从原始请求中获取正文 . 它正在将响应主体构建回API网关 . 它应该是这种格式,

    {
        "statusCode": httpStatusCode,
        "headers": { "headerName": "headerValue", ... },
        "body": "...",
        "isBase64Encoded": false
    }
    
  • 34

    我认为使用API Gateway与Lambda集成时需要了解一些事项 .

    Lambda集成与Lambda代理集成

    过去只有Lambda Integration需要映射模板 . 我想这就是为什么仍然会看到许多使用它的例子 .

    截至2017年9月,您不再需要配置映射来访问请求正文 .

    Lambda代理集成,如果启用它,API Gateway会将每个请求映射到JSON,并将其作为事件对象传递给Lambda . 在Lambda函数中,您将能够从中检索查询字符串参数, Headers ,阶段变量,路径参数,请求上下文和正文 . 如果不启用Lambda代理集成,则必须在API网关的“集成请求”部分中创建映射模板,并决定如何自己将HTTP请求映射到JSON . 如果要将信息传递回客户端,则可能必须创建集成响应映射 . 在添加Lambda代理集成之前,用户被迫手动映射请求和响应,这是令人惊愕的一个来源,尤其是对于更复杂的映射 .

    body是转义字符串,而不是JSON

    使用Lambda代理集成,lambda事件中的正文是一个使用反斜杠转义的字符串,而不是JSON .

    "body": "{\"foo\":\"bar\"}"
    

    如果在JSON格式化程序中测试 .

    Parse error on line 1:
    {\"foo\":\"bar\"}
    -^
    Expecting 'STRING', '}', got 'undefined'
    

    以下文件是关于答复,但它应适用于请求 .

    如果要返回JSON,则body字段必须转换为字符串,否则将导致响应进一步出现问题 . 您可以使用JSON.stringify在Node.js函数中处理此问题;其他运行时需要不同的解决方案,但概念是相同的 .

    要让JavaScript作为JSON对象访问它,需要使用JapaScript中的json.parse,Python中的json.dumps将其转换回JSON对象 .

    字符串对于传输非常有用,但您希望能够将它们转换回客户端和/或服务器端的JSON对象 .

    AWS documentation显示了该怎么做 .

    if (event.body !== null && event.body !== undefined) {
        let body = JSON.parse(event.body)
        if (body.time) 
            time = body.time;
    }
    ...
    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);
    
  • 0

    我和Zappa一起使用lambda;我用json格式的POST发送数据:

    我的basic_lambda_pure.py代码是:

    import time
    import requests
    import json
    def my_handler(event, context):
        print("Received event: " + json.dumps(event, indent=2))
        print("Log stream name:", context.log_stream_name)
        print("Log group name:",  context.log_group_name)
        print("Request ID:", context.aws_request_id)
        print("Mem. limits(MB):", context.memory_limit_in_mb)
        # Code will execute quickly, so we add a 1 second intentional delay so you can see that in time remaining value.
        print("Time remaining (MS):", context.get_remaining_time_in_millis())
    
        if event["httpMethod"] == "GET":
            hub_mode = event["queryStringParameters"]["hub.mode"]
            hub_challenge = event["queryStringParameters"]["hub.challenge"]
            hub_verify_token = event["queryStringParameters"]["hub.verify_token"]
            return {'statusCode': '200', 'body': hub_challenge, 'headers': 'Content-Type': 'application/json'}}
    
        if event["httpMethod"] == "post":
            token = "xxxx"
        params = {
            "access_token": token
        }
        headers = {
            "Content-Type": "application/json"
        }
            _data = {"recipient": {"id": 1459299024159359}}
            _data.update({"message": {"text": "text"}})
            data = json.dumps(_data)
            r = requests.post("https://graph.facebook.com/v2.9/me/messages",params=params, headers=headers, data=data, timeout=2)
            return {'statusCode': '200', 'body': "ok", 'headers': {'Content-Type': 'application/json'}}
    

    我得到了下一个json响应:

    {
    "resource": "/",
    "path": "/",
    "httpMethod": "POST",
    "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "deflate, gzip",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-Country": "US",
    "Content-Type": "application/json",
    "Host": "ox53v9d8ug.execute-api.us-east-1.amazonaws.com",
    "Via": "1.1 f1836a6a7245cc3f6e190d259a0d9273.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "LVcBZU-YqklHty7Ii3NRFOqVXJJEr7xXQdxAtFP46tMewFpJsQlD2Q==",
    "X-Amzn-Trace-Id": "Root=1-59ec25c6-1018575e4483a16666d6f5c5",
    "X-Forwarded-For": "69.171.225.87, 52.46.17.84",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https",
    "X-Hub-Signature": "sha1=10504e2878e56ea6776dfbeae807de263772e9f2"
    },
    "queryStringParameters": null,
    "pathParameters": null,
    "stageVariables": null,
    "requestContext": {
    "path": "/dev",
    "accountId": "001513791584",
    "resourceId": "i6d2tyihx7",
    "stage": "dev",
    "requestId": "d58c5804-b6e5-11e7-8761-a9efcf8a8121",
    "identity": {
    "cognitoIdentityPoolId": null,
    "accountId": null,
    "cognitoIdentityId": null,
    "caller": null,
    "apiKey": "",
    "sourceIp": "69.171.225.87",
    "accessKey": null,
    "cognitoAuthenticationType": null,
    "cognitoAuthenticationProvider": null,
    "userArn": null,
    "userAgent": null,
    "user": null
    },
    "resourcePath": "/",
    "httpMethod": "POST",
    "apiId": "ox53v9d8ug"
    },
    "body": "eyJvYmplY3QiOiJwYWdlIiwiZW50cnkiOlt7ImlkIjoiMTA3OTk2NDk2NTUxMDM1IiwidGltZSI6MTUwODY0ODM5MDE5NCwibWVzc2FnaW5nIjpbeyJzZW5kZXIiOnsiaWQiOiIxNDAzMDY4MDI5ODExODY1In0sInJlY2lwaWVudCI6eyJpZCI6IjEwNzk5NjQ5NjU1MTAzNSJ9LCJ0aW1lc3RhbXAiOjE1MDg2NDgzODk1NTUsIm1lc3NhZ2UiOnsibWlkIjoibWlkLiRjQUFBNHo5RmFDckJsYzdqVHMxZlFuT1daNXFaQyIsInNlcSI6MTY0MDAsInRleHQiOiJob2xhIn19XX1dfQ==",
    "isBase64Encoded": true
    }
    

    我的数据是 body 键,但是是64位编码的,我怎么知道这个?我看到了钥匙 isBase64Encoded

    我复制了body键的值并用This tool和"eureka"解码,我得到了值 .

    我希望这对你有帮助 . :)

相关问题