Obtener el cuerpo json en aws Lambda a través de API gateway


Actualmente estoy usando NodeJS para crear un bot en AWS lambda a través de AWS Api Gateway y me estoy topando con un problema con las solicitudes POST y los datos JSON. Mi api usa 'Use Lambda Proxy integration' e incluso cuando pruebo el proxy enviando un tipo de contenido de Aplicación / json y algo de json en el cuerpo, por ejemplo {"foo":"bar"} No puedo acceder al objeto sin analizarlo primero

E. g

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

Ahora sé que esto no parece un gran problema simplemente ejecutándolo a través de JSON.analizar, pero he visto un número de otros ejemplos donde este no es el caso en absoluto. ver aquí https://github.com/pinzler/fb-messenger-bot-aws-lambda/blob/master/index.js

¿Necesito agregar algo a mi API gateway para manejar esto correctamente? mi paso 'cuerpo de la solicitud 'en la sección' solicitud de método post ' tiene un tipo de contenido de aplicación/configuración json para el cuerpo de la solicitud.

El readme para el ejemplo anterior no parece usar la integración de proxy por lo que puedo decir, así que no estoy seguro de lo que debería estar haciendo aquí

Author: TommyBs, 2017-01-14

3 answers

Hay dos integraciones Lambda diferentes que puede configurar en API Gateway, como la integración Lambda y la integración de proxy Lambda. Para Lambda integration , puede personalizar lo que va a pasar a Lambda en la carga útil que no necesita analizar el cuerpo, pero cuando está utilizando Lambda Proxy integration en API Gateway, API Gateway proxy todo a Lambda en la carga útil de esta manera,

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

Para el ejemplo que está haciendo referencia, no está obteniendo el cuerpo de la solicitud original. Está construyendo el cuerpo de respuesta de nuevo a API Gateway. Debe estar en este formato,

{
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "body": "...",
    "isBase64Encoded": false
}
 23
Author: Ka Hou Ieong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-25 20:38:39

Creo que hay algunas cosas que entender cuando se trabaja con la integración de API Gateway con Lambda.

Integración Lambda vs Integración Lambda Proxy

Solía haber solo integración Lambda que requiere plantillas de asignación. Supongo que es por eso que aún veo muchos ejemplos usándolo.

  • Cómo pasar un parámetro de ruta o querystring a AWS Lambda desde Amazon API Gateway

    A partir de septiembre de 2017, ya no tiene que configure las asignaciones para acceder al cuerpo de la solicitud.

  • Arquitectura sin servidor en AWS

    Integración de proxy Lambda, si la habilita, API Gateway asignará cada solicitud a JSON y la pasará a Lambda como el objeto de evento. En la función Lambda podrá recuperar parámetros de cadena de consulta, encabezados, variables de etapa, parámetros de ruta, contexto de solicitud y el cuerpo de la misma.

    Sin habilitar la integración de Lambda Proxy, tendrá para crear una plantilla de asignación en la sección Solicitud de integración de API Gateway y decidir cómo asignar la solicitud HTTP a JSON usted mismo. Y es probable que tenga que crear una asignación de respuesta de integración si tuviera que pasar información al cliente.

    Antes de que se agregara la integración de Proxy Lambda, los usuarios se veían obligados a asignar solicitudes y respuestas manualmente, lo que era una fuente de consternación, especialmente con asignaciones más complejas.

El cuerpo es cadena de escape, no JSON

Usando la integración de proxy Lambda, el cuerpo en el caso de lambda es una cadena escapada con barra invertida, no un JSON.

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

Si se prueba en un formateador JSON.

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

El documento a continuación es sobre la respuesta, pero debe aplicarse a la solicitud.

Para que JavaScript pueda acceder a él como un objeto JSON, es necesario convertirlo de nuevo en un objeto JSON con json.analizar en JapaScript, json.volcados en Python.

  • Cómo trabajar con JSON en JavaScript

    Las cadenas son útiles para transportarlos, pero querrá ser capaz de convertirlos de nuevo a un objeto JSON en el lado del cliente y/o del servidor.

La documentación de AWS muestra qué hacer.

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);
 3
Author: mon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-08 23:25:55

Estoy usando lambda con Zappa; Estoy enviando datos con POST en formato json:

Mi código para basic_lambda_pure.py is:

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

Tengo la siguiente respuesta 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
}

Mis datos estaban en la clave body , pero code64 está codificado, ¿Cómo puedo saber esto? Vi la clave isBase64Encoded

Copio el valor para body key y decodifico con Esta herramienta y "eureka", obtengo los valores.

Espero que esto te ayude. :)

 0
Author: Te ENe Te,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-22 05:25:18