Erhalten von json body in aws Lambda über das API-Gateway

84

Ich verwende derzeit NodeJS, um einen Bot auf AWS Lambda über AWS Api Gateway zu erstellen, und stoße auf ein Problem mit POST-Anforderungen und JSON-Daten. Meine API verwendet 'Lambda-Proxy-Integration verwenden' und selbst wenn ich den Proxy teste, der einen Inhaltstyp von Application / json und etwas json im Body sendet, {"foo":"bar"}kann ich beispielsweise nicht auf das Objekt zugreifen, ohne es vorher zu analysieren

z.B

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

Jetzt weiß ich, dass dies keine große Sache zu sein scheint, wenn man es nur über JSON.parse ausführt, aber ich habe eine Reihe anderer Beispiele gesehen, bei denen dies überhaupt nicht der Fall ist. siehe hier https://github.com/pinzler/fb-messenger-bot-aws-lambda/blob/master/index.js

Muss ich meinem API-Gateway etwas hinzufügen, um dies korrekt zu handhaben? Mein Schritt 'Anfragetext' im Abschnitt 'Anforderung nach der Methode' enthält einen Inhaltstyp für die Anwendung / JSON-Einrichtung für den Anfragetext.

Die Readme-Datei für das obige Beispiel scheint, soweit ich das beurteilen kann, keine Proxy-Integration zu verwenden, daher bin ich mir nicht sicher, was ich hier tun soll

TommyBs
quelle

Antworten:

71

Es gibt zwei verschiedene Lambda-Integrationen, die Sie in API Gateway konfigurieren können, z. B. die Lambda-Integration und die Lambda-Proxy-Integration. Für die Lambda-Integration können Sie anpassen, was an Lambda in der Nutzlast übergeben werden soll, die Sie nicht zum Analysieren des Körpers benötigen. Wenn Sie jedoch die Lambda-Proxy-Integration in API Gateway verwenden, wird API Gateway alles in Nutzlast an Lambda weiterleiten so was,

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

In dem Beispiel, auf das Sie verweisen, wird der Text nicht aus der ursprünglichen Anforderung abgerufen. Es erstellt den Antworttext zurück zum API-Gateway. Es sollte in diesem Format sein,

{
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "body": "...",
    "isBase64Encoded": false
}
Ka Hou Ieong
quelle
23
und dann JSON.parse (event.body) (Lambda-Proxy-Integration)
timhc22
3
@ timhc22 Dies ist der Hauptpunkt, die eine einzelne Zeile sollte die akzeptierte Antwort sein
5413668060
49

Ich denke, es gibt ein paar Dinge zu verstehen, wenn Sie mit der API-Gateway-Integration mit Lambda arbeiten.

Lambda-Integration vs Lambda-Proxy-Integration

Früher gab es nur die Lambda-Integration, für die Mapping-Vorlagen erforderlich sind. Ich nehme an, deshalb sehen wir immer noch viele Beispiele, die es verwenden.

  • So übergeben Sie einen Querystring- oder Routenparameter vom Amazon API Gateway an AWS Lambda

    Ab September 2017 müssen Sie keine Zuordnungen mehr konfigurieren, um auf den Anforderungshauptteil zuzugreifen.

  • Serverlose Architektur unter AWS

    Lambda-Proxy-Integration: Wenn Sie diese Option aktivieren, ordnet API Gateway jede Anforderung JSON zu und übergibt sie als Ereignisobjekt an Lambda. In der Lambda-Funktion können Sie Abfragezeichenfolgenparameter, Header, Stufenvariablen, Pfadparameter, Anforderungskontext und den Hauptteil daraus abrufen.

    Ohne die Lambda-Proxy-Integration zu aktivieren, müssen Sie im Abschnitt "Integrationsanforderung" von API Gateway eine Zuordnungsvorlage erstellen und selbst entscheiden, wie die HTTP-Anforderung JSON zugeordnet werden soll. Und Sie müssten wahrscheinlich eine Integration Response-Zuordnung erstellen, wenn Sie Informationen an den Client zurückgeben möchten.

    Bevor die Lambda-Proxy-Integration hinzugefügt wurde, mussten Benutzer Anforderungen und Antworten manuell zuordnen , was insbesondere bei komplexeren Zuordnungen zu Bestürzung führte.

body ist ein Escape-String, nicht JSON

Bei Verwendung der Lambda-Proxy-Integration ist der Body bei Lambda eine Zeichenfolge, die mit einem Backslash maskiert ist, kein JSON.

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

Wenn in einem JSON-Formatierer getestet.

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

Das folgende Dokument befasst sich mit der Antwort, sollte jedoch für Anfragen gelten.

Damit JavaScript als JSON-Objekt darauf zugreifen kann, muss es mit json.parse in JapaScript und json.dumps in Python wieder in ein JSON-Objekt konvertiert werden.

  • So arbeiten Sie mit JSON in JavaScript

    Zeichenfolgen sind für den Transport nützlich, möchten sie jedoch wieder in ein JSON-Objekt auf der Client- und / oder Serverseite konvertieren können .

Die AWS-Dokumentation zeigt, was zu tun ist.

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);
mon
quelle
Vielen Dank für den Hinweis, dass der Körper nur Escape-Zeichenfolge NICHT JSON ist.
nngeek
1

Ich benutze Lambda mit Zappa; Ich sende Daten mit POST im JSON-Format:

Mein Code für basic_lambda_pure.py lautet:

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

Ich habe die nächste Antwort von json erhalten:

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

Meine Daten befanden sich auf dem Body- Key, sind jedoch mit Code64 codiert. Woher weiß ich das? Ich habe gesehen, dass der Schlüssel Base64Encoded ist

Ich kopiere den Wert für den Body Key und dekodiere mit diesem Tool und "eureka", ich erhalte die Werte.

Ich hoffe das hilft dir. :) :)

Egalicia
quelle