Помилка лямбда-API API AWS “Неправильна відповідь проксі-відповіді Лямбда”


83

Я намагаюся встановити привіт світового прикладу з лямбда-сигналом AWS і обслуговувати його через шлюз api. Я натиснув "Створити лямбда-функцію", яка налаштувала шлюз api та вибрала параметр Пуста функція. Я додав лямбда-функцію, знайдену в посібнику з початку роботи шлюзу AWS :

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

Справа в тому, що коли я роблю запит GET, він повертає відповідь 502 { "message": "Internal server error" }. А в журналах написано "Виконання не вдалося через помилку конфігурації: Неправильна відповідь проксі-відповіді Лямбда".

Відповіді:


111

Зазвичай, коли ви бачите Malformed Lambda proxy response, це означає, що ваша відповідь від вашої функції Lambda не відповідає формату очікуваного шлюзу API, наприклад

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

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

Крім того, якщо ви бачите переривчастий Malformed Lambda proxy response, це може означати, що запит до вашої функції Лямбда був задушений Лямбдою, і вам потрібно подати запит на одночасне збільшення ліміту виконання функції Лямбда.



4
Ось стаття підтримки AWS щодо неї: aws.amazon.com/premiumsupport/knowledge-center/…
craigmichaelmartin

Ця відповідь була справді корисною. Дякую!
Waleed93,

49

Якщо лямбда використовується як проксі, тоді формат відповіді повинен бути

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

Примітка: Тіло має бути строгим


Якщо "відповідь" - це ім'я вашого об'єкта, використання JSON.stringify (відповідь) не працює. Залишити це так, мені це вдалося. callback(null,response);
Нео,

4
@Neo Вам не потрібно наводити об'єкт відповіді на роздільні символи. Вам потрібно розшифрувати дані всередині ключа тіла об’єкта відповіді
самонавчання91

З цікавості - навіщо тілу потрібно стригувати? Це було моє видання щодо того, над чим я працював, і це мене збентежило - спасибі
andy mccullough

2
З них лише statusCodeдля успішного виклику з API Gateway.
Трентон,

Забезпечення строгості тіла працювало для мене. Велике спасибі +1
Кімутай

25

Так, я думаю, це пов’язано з тим, що ви насправді не повертаєте туди належної відповіді http, саме тому ви отримуєте помилку.

особисто я використовую набір таких функцій:

    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.

Тоді ви просто робите:

var responder = require('responder')

// some code

callback(null, responder.success({ message: 'hello world'}))

Тепер, якщо ми використовуємо значення Access-Control-Allow-Credentials як true, ми не можемо зберігати значення 'Access-Control-Allow-Origin' як '*'
Santhosh Nagulanchi

1
Я помітив, що він підтримує лише один заголовок Origin: {"Access-Control-Allow-Origin": "<< Єдиний домен >>", "Access-Control-Allow-Credentials": true // Потрібно для файлів cookie, заголовків авторизації HTTPS},
Santhosh Nagulanchi

6

З документів AWS

У функції Лямбда в Node.js для повернення успішної відповіді потрібно викликати зворотний виклик (null, {"statusCode": 200, "body": "results"}). Щоб видалити виняток, викличте зворотний виклик (нова помилка ('внутрішня помилка сервера')). Для помилки на стороні клієнта, наприклад, відсутній необхідний параметр, ви можете викликати зворотний виклик (null, {"statusCode": 400, "body": "Відсутні параметри ..."}), щоб повернути помилку, не видаючи виняток.


5

Для 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
    }

Зверніть увагу, що bodyне потрібно встановлювати, він може бути просто порожнім:

        'body': ''

3

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

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

Але Amazon потребує цього:

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


3

Для всіх, хто бореться, коли відповідь виявляється дійсним. Це не працює:

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

але це робить:

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

Крім того, схоже, що ніякі зайві ключі не можуть бути присутніми на об'єкті відповіді.


3

Якщо ви використовуєте Go з https://github.com/aws/aws-lambda-go , вам доведеться використовувати events.APIGatewayProxyResponse.

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

3

Я спробував усі вищезазначені пропозиції, але це не працює, поки bodyзначення не єString

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

3

Просто шматок коду для .net core і 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;

Відповідь лямбда буде:

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

Відповідь шлюзу api буде:

{"msg":"Welcome to Belarus! :)"}

1
OMG, велике спасибі, ти щойно врятував мене через кілька годин, намагаючись зрозуміти, як здивовано отримати заголовок у відповіді. Я спробував звичайний JSON, не працював. Я пробував пари ключових значень, не працював. Словник - це шлях! ДЯКУЮ!
Міша

1

У мене сталася ця помилка, оскільки я випадково видалив змінну ServerlessExpressLambdaFunctionName із ресурсу CloudFormation AWS :: Serverless :: Api. Контекст тут https://github.com/awslabs/aws-serverless-express "Запустіть безсерверні програми та REST API, використовуючи існуючу структуру додатків Node.js, поверх AWS Lambda та Amazon API Gateway"


0

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

Я здійснював дзвінок до бази даних RDS у своїй функції. Виявилося, що причиною проблеми були правила групи безпеки (вхідні) у цій базі даних.

Можливо, вам захочеться обмежити IP-адреси, які можуть отримати доступ до API, але якщо ви хочете, щоб він працював швидко / брудно, щоб перевірити, чи ця зміна виправляє, ви можете встановити, щоб він приймав все подібне (ви також можете встановити діапазон на порти, щоб прийняти всі порти теж, але я не робив цього в цьому прикладі):

введіть тут опис зображення


0

Поширеною причиною помилки "Неправильно сформована відповідь проксі Лямбда" є headersте, що не є {String: String, ...}парами ключ / значення.

Оскільки set-cookieзаголовки можуть і з'являтися в упаковці, вони представлені в http.request.callback.response як set-cookieключ , який має Arrayвід Strings вартості , а не в одногоString . Хоча це працює для розробників, шлюз API AWS цього не розуміє і видає помилку "Неправильна відповідь лямбда-проксі-відповіді".

Моє рішення - зробити щось подібне:

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

Зверніть увагу, що ...вищезазначене не означає Яда Яда Яда . Це оператор поширення ES6 .


0

Ось ще один підхід. Налаштуйте шаблон відображення у своєму запиті та відповіді на інтеграцію шлюзу API. Перейдіть до IntegrationRequest -> MappingTemplate -> виберіть "Коли шаблони не визначені" -> введіть application / json для типу вмісту. Тоді вам не потрібно явно надсилати json. Навіть відповідь, яку ви отримаєте від свого клієнта, може бути простим рядком.


0

Формат відповіді вашої функції є джерелом цієї помилки. Щоб шлюз API обробляв відповідь лямбда-функції, відповідь має бути JSON у такому форматі:

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

Ось приклад функції в Node.js із правильно відформатованою відповіддю:

export.handler = (подія, контекст, зворотний виклик) => {

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

};

Посилання: https://aws.amazon.com/premiumsupport/knowledge-center/malformed-502-api-gateway/


0

Python 3.7

Раніше

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

Після

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

0

Якщо ви лише новачок у AWS і хочете, щоб ваша URL-адреса працювала,

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

Перейдіть до додатка API Gateway -> Виберіть свій конкретний лямбда-шлюз API (Виконання методу) -> Клацніть на Запит на ІНТЕГРАЦІЮ -> Зніміть прапорець біля пункту «Використовувати інтеграцію лямбда-проксі» (прапорець).

Потім натисніть « <-Виконання методу » та клацніть на розділі «Тестування клієнта». Введіть параметри та натисніть кнопку перевірки. Ви повинні побачити відповідь на успіх.

Якщо ви все ще не можете отримати відповідь на успіх, створіть псевдонім для правильної версії (якщо у вас є кілька версій у лямбда-функції)

Виберіть URL-адресу з журналів та скористайтеся інструментом POST / GET (Листоноша) та виберіть автентифікацію як підпис AWS - надайте ключі автентифікації (AccessKey & SecretKey) у запиті листоноші з назвою AWS Region & Service Name як лямбда.

PS: Це може допомогти лише новачкам, а для інших може бути неактуальним.

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