Отримання тіла json в aws Lambda через шлюз API


84

В даний час я використовую NodeJS для створення бота на лямбда-каналі AWS через шлюз Api Api, і я стикаюся з проблемою із запитами POST та даними JSON. Мій api використовує "Використовувати інтеграцію лямбда-проксі", і навіть коли я тестую проксі-сервер, що надсилає вміст типу Application / json і деякий json в тілі, наприклад, {"foo":"bar"}я не можу отримати доступ до об'єкта, не проаналізувавши його спочатку

напр

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

Тепер я знаю, що це не здається великою проблемою, якщо просто запустити його через JSON.parse, але я бачив ряд інших прикладів, коли це зовсім не так. дивіться тут https://github.com/pinzler/fb-messenger-bot-aws-lambda/blob/master/index.js

Чи потрібно мені щось додавати до мого шлюзу API, щоб це правильно обробляти? мій крок "тіло запиту" у розділі "запит методу повідомлення" має тип контенту програми / json, встановленого для тіла запиту.

У readme для наведеного вище прикладу, наскільки я можу зрозуміти, не використовується інтеграція проксі, тому я не впевнений, що мені тут робити

Відповіді:


71

У шлюзі API можна налаштувати дві різні інтеграції Lambda, такі як інтеграція Lambda та інтеграція проксі-сервера Lambda. Для інтеграції Lambda ви можете налаштувати те, що ви збираєтесь передавати Lambda в корисному навантаженні, що не потрібно для синтаксичного аналізу тіла, але коли ви використовуєте інтеграцію Lambda Proxy в API Gateway, API Gateway буде проксі-сервером для 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 Gateway. Це має бути в такому форматі,

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

23
а потім JSON.parse (event.body) (інтеграція лямбда-проксі)
timhc22

3
@ timhc22 це головне, єдиним рядком повинна бути прийнята відповідь
5413668060

50

Я думаю, є кілька речей, які слід зрозуміти під час роботи з інтеграцією шлюзу API із Lambda.

Лямбда-інтеграція проти інтеграції Лямбда-проксі

Раніше існувала лише лямбда-інтеграція, яка вимагає шаблонів відображення. Я вважаю, саме тому все ще бачу багато прикладів, що використовують його.

  • Як передати рядок запиту або параметр маршруту до AWS Lambda із шлюзу Amazon API

    З вересня 2017 року вам більше не потрібно налаштовувати зіставлення для доступу до тіла запиту.

  • Безсерверна архітектура на AWS

    Інтеграція лямбда-проксі. Якщо ви ввімкнете його, шлюз API буде відображати кожен запит до JSON і передавати його Лямбді як об’єкт події. У функції Лямбда ви зможете отримати з нього параметри рядка запиту, заголовки, змінні етапу, параметри шляху, контекст запиту та тіло.

    Не вмикаючи інтеграцію лямбда-проксі, вам доведеться створити шаблон зіставлення у розділі Запит на інтеграцію API-шлюзу та вирішити, як самостійно зіставити HTTP-запит із JSON. І вам, швидше за все, доведеться створити зіставлення відповіді інтеграції, якщо ви хочете передати інформацію клієнту.

    До того, як було додано Lambda Proxy Integration, користувачі були змушені зіставляти запити та відповіді вручну, що викликало занепокоєння , особливо при більш складних відображеннях.

body - це рядок, що не використовується, а не JSON

Використовуючи інтеграцію лямбда-проксі, тілом у разі лямбда є рядок, екранований косою рисою, а не JSON.

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

Якщо тестується у форматері JSON.

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

У наведеному нижче документі йдеться про відповідь, але він повинен застосовуватися до запиту.

Щоб JavaScript отримав доступ до нього як об’єкт JSON, потрібно перетворити його назад у об’єкт JSON за допомогою json.parse у JapaScript, json.dumps у Python.

  • Як працювати з JSON в JavaScript

    Рядки корисні для транспортування, але ви хочете мати можливість перетворити їх назад у об'єкт JSON на стороні клієнта та / або сервера.

Документація AWS показує, що робити.

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

Дякуємо, що вказали на те, що тіло просто уникло рядка NOT JSON.
nngeek

1

Я використовую лямбду з Zappa; Я надсилаю дані за допомогою POST у форматі json:

Мій код для 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
}

мої дані були на тілі ключа, але code64 кодований, Як я можу це знати? Я побачив, що ключ isBase64Encoded

Я копіюю значення ключа тіла та декодую за допомогою цього інструменту та "eureka", я отримую значення.

Сподіваюся, це вам допоможе. :)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.