Обработка ошибок AWS Lambda с помощью API Gateway

У меня class BadRequest(Exception): pass в моей лямбда-функции.

Я хочу raise BadRequest("Invalid request params"), чтобы API возвращал ответ с кодом состояния 400 и телом { "message": "Invalid request params" } (или эквивалентным).

Однако простое выполнение этого возвращает ответ с кодом состояния 200 (о нет!) И телом.

{
    "errorMessage": "Invalid request params",
    "errorType": "BadRequest",
    "stackTrace": <my application code that the user shouldnt see>
}

После поиска в Интернете, похоже, у меня есть 3 варианта:

1) chalice

2) Используйте интеграционный ответ и ответ метода, чтобы проанализировать эту ошибку и получить лучший ответ. Я бы использовал регулярное выражение типа [BadRequest].* и вставлял префикс, когда я генерирую исключение (не очень элегантный IMO).

3) Используйте Step Functions, чтобы создать представление API с отслеживанием состояния. Это кажется немного утомительным, потому что мне нужно выучить ASL, а я не знаю глухих. -.-

-.- язык состояний amazon


В какую кроличью нору мне спуститься и почему?


comment
Не очень разбираясь в функциях чаши и ступени. Я бы рекомендовал использовать ответ интеграции и ответ метода для этой лямбды. Это функция, построенная для решения такого рода проблем, и я использую ее везде, чтобы форматировать свои ответы на основе определенных триггеров. Основная причина выбора этого пути заключается в том, что он поддерживается AWS для решения этой проблемы для сервиса AWS. Таким образом, меньше накладных расходов на управление для вас или того, кто возьмет на себя этот проект в будущем. Кроме того, это не так сложно изучить, и вы также можете писать документы синтаксиса json для входящих данных.   -  person asdf    schedule 17.06.2017
comment
Допустим, возникло неизвестное исключение (например, TypeError), и я не знаю префикс. Как мне избежать ответа 200 / traceback в этом случае?   -  person woodpav    schedule 17.06.2017
comment
См. Также это сообщение в блоге: [Шаблоны обработки ошибок в Amazon API Gateway и AWS Lambda] (aws.amazon.com/blogs/compute/)   -  person bejos-aws    schedule 18.06.2017


Ответы (4)


Я возвращаюсь к этому вопросу 3 года спустя, чтобы описать, как я решаю эту проблему сегодня. Я использую Serverless Framework для развертывания своих лямбда-функций и шлюза API.

Я использую декоратор, который ловит исключения и возвращает полезную нагрузку. Например, вот успешный запрос, ожидаемое исключение и неожиданное исключение.

def my_successful_request(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps({"success": True})
    }


def handle_exceptions(f):
    def deco(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except BadRequest as e:
            print(e)
            return {"statusCode": 400, "body": json.dumps({"message": str(e)})}
        except Exception as e:
            print(e)
            return {"statusCode": 500, "body": json.dumps({"message": "unexpected error"})}
    return deco

@handle_exceptions
def my_expected_error_request(event, context):
    raise BadRequest("This function raises a BadRequest with a 400 status code that should be sent to the user. The end user can read this text.")

@handle_exceptions
def my_unexpected_error_request(event, context):
    raise Exception("Uh oh. I didn't expect this. A 500 error with an obfuscated message is raised. The end user cannot read this text.")

Этот шаблон позволяет API очень легко возвращать соответствующее сообщение об ошибке и код состояния. У меня очень элементарное ведение журнала в этой handle_exceptions реализации, но вы можете получать действительно подробные сообщения с f.__name__, чтобы узнать, какая функция лямбда ошиблась, и модуль трассировки, чтобы понять источник исключения. Все это управление ошибками полностью скрыто от пользователя API.

person woodpav    schedule 13.08.2020

Chalice значительно упрощает реализацию REST API с Lambda и API Gateway, включая преобразование возбужденных исключений в ответы. В вашем конкретном случае вы должны создать такое исключение:

import chalice
app = chalice.Chalice(app_name='your-app')
app.debug = True  # Includes stack trace in response. Set to False for production.

@app.route('/api', methods=['GET'])
def your_api():
    raise chalice.BadRequestError("Your error message")

На GitHub есть полный рабочий пример REST API, который использует Chalice с Lambda и API Gateway: aws-doc-sdk-examples.

person Laren Crawford    schedule 03.08.2020

Вы должны перехватить исключение в Lambda и выбросить настраиваемое исключение, как показано ниже.

public class LambdaFunctionHandler implements RequestHandler<String, String> {
  @Override
    public String handleRequest(String input, Context context) {

        Map<String, Object> errorPayload = new HashMap();
        errorPayload.put("errorType", "BadRequest");
        errorPayload.put("httpStatus", 400);
        errorPayload.put("requestId", context.getAwsRequestId());
        errorPayload.put("message", "Invalid request params " + stackstace);
        String message = new ObjectMapper().writeValueAsString(errorPayload);

        throw new RuntimeException(message);
    }
}

And then use Option 2  to map the error code .

Integration response:
Selection pattern: “.*"BadRequest".*”

Method response: 500

Mapping template:

#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))
{
  "type" : "$errorMessageObj.errorType",
  "message" : "$errorMessageObj.message",
  "request-id" : "$errorMessageObj.requestId"
}
person dassum    schedule 22.07.2017

Это идеальный вариант использования AWS Step Functions. Вам нужно будет настроить API Gateway для прямого вызова конечного автомата, который вы создадите.

Вот ASL ​​для вышеупомянутого конечного автомата:

{
  "Comment": "A state machine that executes my lambda function and catches the bad error.",
  "StartAt": "MyLambda",
  "States": {
    "MyLambda": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
      "Catch": [
        {
          "ErrorEquals": ["BadError"],
          "Next": "BadErrorFallback"
        }
      ],
      "End": true
    },
    "BadErrorFallback": {
      "Type": "Pass",
      "Result": "Put here whatever is the result that you want to return.",
      "End": true
    }
  }
}

Это будет запускать предоставленные вами лямбда-функции. Если лямбда-функция выдает ошибку BadError, она выводит результат состояния BadErrorFallback. В противном случае он будет выводить все, что выдаст лямбда-функция.

Надеюсь это поможет!

person SunnyD    schedule 03.11.2017