Nhận json body trong aws Lambda qua cổng API


84

Tôi hiện đang sử dụng NodeJS để xây dựng một bot trên AWS lambda thông qua AWS Api Gateway và tôi đang gặp sự cố với các yêu cầu POST và dữ liệu JSON. Api của tôi sử dụng 'Sử dụng tích hợp Lambda Proxy' và ngay cả khi tôi kiểm tra proxy gửi một loại nội dung của Ứng dụng / json và một số json trong phần thân, ví dụ: {"foo":"bar"}tôi không thể truy cập đối tượng mà không phân tích cú pháp nó trước.

ví dụ

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

Bây giờ tôi biết điều này có vẻ không phải là một vấn đề lớn nếu chỉ chạy nó qua JSON.parse, nhưng tôi đã thấy một số ví dụ khác trong đó điều này hoàn toàn không đúng. xem ở đây https://github.com/pinzler/fb-messenger-bot-aws-lambda/blob/master/index.js

Tôi có cần thêm bất kỳ thứ gì vào cổng API của mình để xử lý điều này một cách chính xác không? bước 'request body' của tôi trong phần 'post method request' có một loại ứng dụng / json nội dung được thiết lập cho phần thân yêu cầu.

Readme cho ví dụ trên dường như không sử dụng tích hợp proxy theo như tôi có thể nói nên tôi không chắc mình nên làm gì ở đây

Câu trả lời:


71

Có hai tích hợp Lambda khác nhau mà bạn có thể định cấu hình trong API Gateway, chẳng hạn như tích hợp Lambda và tích hợp proxy Lambda. Đối với tích hợp Lambda , bạn có thể tùy chỉnh những gì bạn sẽ chuyển đến Lambda trong tải trọng mà bạn không cần phải phân tích cú pháp nội dung, nhưng khi bạn đang sử dụng tích hợp Lambda Proxy trong API Gateway, API Gateway sẽ ủy quyền mọi thứ cho Lambda trong tải trọng như thế này,

{
    "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
    }
}

Đối với ví dụ bạn đang tham khảo, nó không lấy được phần thân từ yêu cầu ban đầu. Nó đang xây dựng cơ quan phản hồi trở lại API Gateway. Nó phải ở định dạng này,

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

23
và sau đó là JSON.parse (event.body) (Tích hợp Lambda Proxy)
timhc22

3
@ timhc22 đây là điểm chính, một dòng duy nhất nên là câu trả lời được chấp nhận
5413668060

49

Tôi nghĩ có một số điều cần hiểu khi làm việc với tích hợp API Gateway với Lambda.

Tích hợp Lambda và Tích hợp proxy Lambda

Trước đây chỉ có Tích hợp Lambda yêu cầu các mẫu ánh xạ. Tôi cho rằng đây là lý do tại sao vẫn thấy nhiều ví dụ sử dụng nó.

  • Cách chuyển chuỗi truy vấn hoặc tham số định tuyến tới AWS Lambda từ Amazon API Gateway

    Kể từ tháng 9 năm 2017, bạn không còn phải định cấu hình ánh xạ để truy cập nội dung yêu cầu.

  • Kiến trúc không máy chủ trên AWS

    Tích hợp Proxy Lambda, Nếu bạn bật nó, API Gateway sẽ ánh xạ mọi yêu cầu tới JSON và chuyển nó đến Lambda dưới dạng đối tượng sự kiện. Trong hàm Lambda, bạn sẽ có thể truy xuất các tham số chuỗi truy vấn, tiêu đề, biến giai đoạn, tham số đường dẫn, ngữ cảnh yêu cầu và nội dung từ nó.

    Nếu không bật Tích hợp proxy Lambda, bạn sẽ phải tạo mẫu ánh xạ trong phần Yêu cầu tích hợp của API Gateway và tự quyết định cách ánh xạ yêu cầu HTTP tới JSON. Và bạn có thể phải tạo ánh xạ Phản hồi tích hợp nếu bạn chuyển thông tin lại cho khách hàng.

    Trước khi Tích hợp Proxy Lambda được thêm vào, người dùng buộc phải lập bản đồ các yêu cầu và phản hồi theo cách thủ công, đây là nguồn gốc của sự biến đổi , đặc biệt là với các ánh xạ phức tạp hơn.

nội dung là chuỗi thoát, không phải JSON

Sử dụng Tích hợp proxy Lambda, nội dung trong trường hợp là lambda là một chuỗi được thoát bằng dấu gạch chéo ngược, không phải là JSON.

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

Nếu được thử nghiệm trong trình định dạng JSON.

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

Tài liệu dưới đây là về phản hồi nhưng nó sẽ áp dụng cho yêu cầu.

Để JavaScript có thể truy cập nó như một đối tượng JSON, cần chuyển đổi nó trở lại thành đối tượng JSON với json.parse trong JapaScript, json.dumps trong Python.

  • Cách làm việc với JSON trong JavaScript

    Các chuỗi hữu ích cho việc vận chuyển nhưng bạn sẽ muốn có thể chuyển đổi chúng trở lại đối tượng JSON trên máy khách và / hoặc phía máy chủ.

Các AWS tài liệu hướng dẫn chương trình phải làm gì.

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);

Cảm ơn bạn đã chỉ ra rằng phần thân chỉ là chuỗi thoát KHÔNG phải JSON.
nngeek

1

Tôi đang sử dụng lambda với Zappa; Tôi đang gửi dữ liệu với POST ở định dạng json:

Mã của tôi cho basic_lambda_pure.py là:

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'}}

Tôi nhận được phản hồi json tiếp theo:

{
"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
}

dữ liệu của tôi ở trên body key, nhưng được mã hóa code64, Làm cách nào để biết được điều này? Tôi thấy khóa isBase64Encoded

Tôi sao chép giá trị cho khóa cơ thể và giải mã bằng Công cụ này và "eureka", tôi nhận được các giá trị.

Tôi hy vọng điều này sẽ giúp bạn. :)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.