Error de puerta de enlace de la API lambda de AWS "Respuesta de proxy Lambda con formato incorrecto"

83

Estoy tratando de configurar un ejemplo de hola mundo con AWS lambda y servirlo a través de la puerta de enlace api. Hice clic en "Crear una función Lambda", que configuró la API Gatway y seleccioné la opción Función en blanco. Agregué la función lambda que se encuentra en la guía de introducción al gateway de AWS :

exports.handler = function(event, context, callback) {
  callback(null, {"Hello":"World"});  // SUCCESS with message
};

El problema es que cuando le hago una solicitud GET, devuelve una respuesta 502 { "message": "Internal server error" }. Y los registros dicen "Error de ejecución debido a un error de configuración: respuesta de proxy Lambda mal formada".

jjbskir
fuente

Respuestas:

111

Por lo general, cuando ve Malformed Lambda proxy response, significa que su respuesta de su función Lambda no coincide con el formato que espera API Gateway, como este

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

Si no está utilizando la integración de proxy de Lambda, puede iniciar sesión en la consola de API Gateway y desmarcar la casilla de verificación Integración de proxy de Lambda.

Además, si observa intermitentes Malformed Lambda proxy response, puede significar que Lambda ha limitado la solicitud a su función Lambda, y debe solicitar un aumento del límite de ejecución simultánea en la función Lambda.

Ka Hou Ieong
fuente
4
Aquí hay un artículo de soporte de AWS al respecto: aws.amazon.com/premiumsupport/knowledge-center/…
craigmichaelmartin
Esta respuesta fue realmente útil. ¡Gracias!
Waleed93
49

Si se utiliza lambda como proxy, el formato de respuesta debe ser

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

Nota: el cuerpo debe estar encordado

autodidacta91
fuente
Si "respuesta" es el nombre de su objeto, el uso de JSON.stringify (respuesta) no funciona. Dejarlo así funcionó para mí. callback(null,response);
Neo
4
@Neo No es necesario especificar el objeto de respuesta. Necesita secuenciar los datos dentro de la clave del cuerpo del objeto de respuesta
selftaught91
Por curiosidad, ¿por qué es necesario encordar el cuerpo? Este fue mi problema en algo en lo que he estado trabajando, y me dejó confundido - gracias
andy mccullough
2
De estos, solo statusCodese requiere para que una llamada desde API Gateway tenga éxito.
Trenton
Asegurar que el cuerpo esté encordado funcionó para mí. Muchas gracias +1
Kimutai
25

Sí, entonces creo que esto se debe a que en realidad no está devolviendo una respuesta http adecuada, por lo que recibe el error.

personalmente uso un conjunto de funciones como esta:

    module.exports = {
        success: (result) => {
            return {
                statusCode: 200,
                headers: {
                    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
                    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
                },
                body: JSON.stringify(result),
            }
        },
        internalServerError: (msg) => {
            return {
                statusCode: 500,
                headers: {
                    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
                    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
                },
                body: JSON.stringify({
                    statusCode: 500,
                    error: 'Internal Server Error',
                    internalError: JSON.stringify(msg),
                }),
            }
        }
} // add more responses here.

Entonces simplemente haces:

var responder = require('responder')

// some code

callback(null, responder.success({ message: 'hello world'}))
Mrk Fldig
fuente
Ahora, si usamos el valor de Access-Control-Allow-Credentials como verdadero, no podemos mantener el valor de 'Access-Control-Allow-Origin' como '*'
Santhosh Nagulanchi
1
Observé que solo admite un Origin: headers: {"Access-Control-Allow-Origin": "<< Single Domain >>", "Access-Control-Allow-Credentials": true // Requerido para cookies, encabezados de autorización con HTTPS},
Santhosh Nagulanchi
6

De los documentos de AWS

En una función Lambda en Node.js, para devolver una respuesta correcta, llame a callback (null, {"statusCode": 200, "body": "results"}). Para lanzar una excepción, llame a callback (new Error ('error interno del servidor')). Para un error del lado del cliente, por ejemplo, falta un parámetro obligatorio, puede llamar a callback (null, {"statusCode": 400, "body": "Missing parameters of ..."}) para devolver el error sin arrojar un excepción.

Jonathan
fuente
5

Para Python3:

import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
        },
        'body': json.dumps({
            'success': True
        }),
        "isBase64Encoded": False
    }

Tenga en bodycuenta que no es necesario configurarlo, solo puede estar vacío:

        'body': ''
perejil72
fuente
3

Un caso muy muy especial, si pasa los encabezados directamente, existe la posibilidad de que tenga este encabezado:

"set-cookie": [ "........" ]

Pero Amazon necesita esto:

"set-cookie": "[ \\"........\\" ]"

Miguel
fuente
3

Para cualquier otra persona que tenga problemas cuando la respuesta parezca válida. Esto no funciona:

callback(null,JSON.stringify( {
  isBase64Encoded: false,
  statusCode: 200,
  headers: { 'headerName': 'headerValue' },
  body: 'hello world'
})

pero esto hace:

callback(null,JSON.stringify( {
  'isBase64Encoded': false,
  'statusCode': 200,
  'headers': { 'headerName': 'headerValue' },
  'body': 'hello world'
})

Además, parece que no se permite que haya claves adicionales en el objeto de respuesta.

Ciryon
fuente
3

Si está usando Go con https://github.com/aws/aws-lambda-go , debe usar events.APIGatewayProxyResponse.

func hello(ctx context.Context, event ImageEditorEvent) (events.APIGatewayProxyResponse, error) {
    return events.APIGatewayProxyResponse{
        IsBase64Encoded: false,
        StatusCode:      200,
        Headers:         headers,
        Body:            body,
    }, nil
}
Kohei Mikami
fuente
3

He intentado todas las sugerencias anteriores, pero no funciona mientras el bodyvalor no lo esString

return {
    statusCode: 200,
    headers: {
        "Content-Type": "application/json",
        "Access-Control-Allow-Origin": "*"
    },
    body: JSON.stringify({
        success: true
    }),
    isBase64Encoded: false
};
Long Nguyen
fuente
3

Solo un fragmento de código para .net core y C # :

using Amazon.Lambda.APIGatewayEvents;
...
var response = new APIGatewayProxyResponse
{
   StatusCode = (int)HttpStatusCode.OK,
   Body = JsonConvert.SerializeObject(new { msg = "Welcome to Belarus! :)" }),
   Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
};
return response;

La respuesta de lambda será:

{"statusCode":200,"headers":{"Content-Type":"application/json"},"multiValueHeaders":null,"body":"{\"msg\":\"Welcome to Belarus! :)\"}","isBase64Encoded":false}

La respuesta de la puerta de enlace de la API será:

{"msg":"Welcome to Belarus! :)"}
Nigrimmist
fuente
1
Dios mío, muchas gracias, me acabas de salvar después de horas de intentar averiguar cómo conseguir un encabezado en la respuesta. Probé JSON simple, no funcionó. Probé pares clave-valor, no funcionó. ¡Diccionario era el camino a seguir! ¡GRACIAS!
Misha
1

Tuve este error porque eliminé accidentalmente la variable ServerlessExpressLambdaFunctionName del recurso CloudFormation AWS :: Serverless :: Api. El contexto aquí es https://github.com/awslabs/aws-serverless-express "Ejecute aplicaciones sin servidor y API REST utilizando su marco de aplicación Node.js existente, además de AWS Lambda y Amazon API Gateway"

marca
fuente
0

En caso de que lo anterior no funcione para nadie, encontré este error a pesar de configurar la variable de respuesta correctamente.

Estaba haciendo una llamada a una base de datos RDS en mi función. Resultó que lo que estaba causando el problema eran las reglas del grupo de seguridad (de entrada) en esa base de datos.

Probablemente desee restringir las direcciones IP que pueden acceder a la API, pero si desea que funcione rápido / sucio para probar si ese cambio lo soluciona, puede configurarlo para que acepte todo así (también puede configurar el rango en los puertos para aceptar todos los puertos también, pero no hice eso en este ejemplo):

ingrese la descripción de la imagen aquí

abe732
fuente
0

Una causa común del error "Respuesta de proxy Lambda con formato incorrecto" es headersque no{String: String, ...} son pares clave / valor.

Desde set-cookielas cabeceras pueden y deben aparecer en múltiplos, que están representados en http.request.callback.response como la set-cookiellave que tiene una Arrayde Strings valor en lugar de una solaString . Si bien esto funciona para los desarrolladores, AWS API Gateway no lo entiende y genera un error de "Respuesta de proxy Lambda mal formada".

Mi solución es hacer algo como esto:

function createHeaders(headers) {
  const singleValueHeaders = {}
  const multiValueHeaders = {}
  Object.entries(headers).forEach(([key, value]) => {
    const targetHeaders = Array.isArray(value) ? multiValueHeaders : singleValueHeaders
    Object.assign(targetHeaders, { [key]: value })
  })

  return {
    headers: singleValueHeaders,
    multiValueHeaders,
  }
}

var output = {
  ...{
    "statusCode": response.statusCode,
    "body": responseString
  },
  ...createHeaders(response.headers)
}

Tenga en cuenta que lo ...anterior no significa Yada Yada Yada . Es el operador de propagación ES6 .

Bruno Bronosky
fuente
0

Aquí hay otro enfoque. Configure la plantilla de asignación en su solicitud y respuesta de integración de puerta de enlace API. Vaya a IntegrationRequest -> MappingTemplate -> seleccione "Cuando no hay plantillas definidas" -> escriba application / json para content-type. Entonces no tiene que enviar explícitamente un json. Incluso la respuesta que recibe de su cliente puede ser una cadena simple.

Sujay DSa
fuente
0

El formato de la respuesta de su función es la fuente de este error. Para que API Gateway maneje la respuesta de una función Lambda, la respuesta debe ser JSON en este formato:

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

Aquí hay una función de ejemplo en Node.js con la respuesta formateada correctamente:

export.handler = (evento, contexto, devolución de llamada) => {

var responseBody = {
    "key3": "value3",
    "key2": "value2",
    "key1": "value1"
};

var response = {
    "statusCode": 200,
    "headers": {
        "my_header": "my_value"
    },
    "body": JSON.stringify(responseBody),
    "isBase64Encoded": false
};
callback(null, response);

};

Ref: https://aws.amazon.com/premiumsupport/knowledge-center/malformed-502-api-gateway/

Ahsan Munawar
fuente
0

Python 3.7

antes de

{
    "isBase64Encoded": False,
    "statusCode": response.status_code,
    "headers": {
                  "Content-Type": "application/json",
               },
     "body": response.json()
}

Después

{
    "isBase64Encoded": False,
    "statusCode": response.status_code,
    "headers": {
                  "Content-Type": "application/json",
               },
     "body": str(response.json()) //body must be of string type
}
Jorge López
fuente
0

Si es nuevo en AWS y solo quiere que su URL funcione,

Si no ha creado un disparador para su función Lambda, navegue hasta la función en la aplicación Lambda Functions y cree un disparador eligiendo API Gateway.

Vaya a la aplicación API Gateway -> Elija su puerta de enlace de API de Lambda particular (ejecución de método) -> Haga clic en Solicitud de INTEGRACIÓN -> Desmarque "Usar integración de proxy de Lambda" (casilla de verificación).

Luego haga clic en " <-Método de ejecución " y haga clic en la sección Probar cliente. Proporcione las opciones y haga clic en el botón de prueba. Debería ver una respuesta de éxito.

Si aún no puede obtener una respuesta satisfactoria, cree un alias para la versión correcta (si tiene varias versiones en la función Lambda)

Elija la URL de los registros y use su herramienta POST / GET (Postman) y elija la autenticación como AWS Signature; proporcione sus claves de autenticación (AccessKey y SecretKey) en la solicitud del cartero con AWS Region & Service Name como lambda.

PD: Esto solo puede ayudar a los principiantes y puede ser irrelevante para otros.

Patricio
fuente