【问题标题】:Handling AWS Lambda errors with API Gateway使用 API Gateway 处理 AWS Lambda 错误
【发布时间】:2020-08-14 01:14:13
【问题描述】:

我的 Lambda 函数中有 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 states language


我应该去哪个兔子洞,为什么?

【问题讨论】:

  • 对圣杯和阶梯函数了解不多。我建议使用该 lambda 的集成响应和方法响应。它是构建 来处理此类问题的功能,我在任何地方都使用它来根据某些触发器格式化我的响应。走这条路的主要原因是 AWS 支持它为 AWS 服务解决这个问题。因此,您或将来接管此项目的任何人的管理开销都会减少。另外,学习起来并不难,你还可以为传入的数据编写 json 语法文档。
  • 假设引发了一个未知异常(比如 TypeError)并且我不知道前缀。在这种情况下如何避免 200/traceback 响应?
  • 另请参阅此博文:[Amazon API Gateway 和 AWS Lambda 中的错误处理模式] (aws.amazon.com/blogs/compute/…)

标签: python amazon-web-services aws-lambda aws-api-gateway aws-step-functions


【解决方案1】:

我在 3 年后回到这个问题来描述我今天是如何解决这个问题的。我使用Serverless Framework 来部署我的 lambda 函数和 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 很容易返回适当的错误消息和 status code。我在这个handle_exceptions 实现中有非常基本的日志记录,但是您可以使用f.__name__ 获得非常详细的消息,以了解错误的Lambda 函数和traceback module 以了解异常的来源。所有这些错误管理对 API 用户完全隐藏。

【讨论】:

    【解决方案2】:

    Chalice 使得使用 Lambda 和 API Gateway 实现 REST API 变得非常简单,包括将引发的异常转换为响应。对于您的特定情况,您会引发这样的异常:

    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

    【讨论】:

      【解决方案3】:

      您应该在 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"
      }
      

      【讨论】:

        【解决方案4】:

        这是 AWS Step Functions 的完美用例。您需要设置 API 网关以直接调用您将创建的状态机。

        这是上述状态机的 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
            }
          }
        }
        

        这将运行您提供的 lambda 函数。如果 lambda 函数抛出 BadError,那么它将输出 BadErrorFallback 状态的结果。否则它将输出 lambda 函数吐出的任何内容。

        希望这会有所帮助!

        【讨论】:

          猜你喜欢
          • 2018-01-15
          • 2021-09-19
          • 2017-06-23
          • 2016-06-02
          • 1970-01-01
          • 2017-07-07
          • 1970-01-01
          • 2017-10-04
          • 1970-01-01
          相关资源
          最近更新 更多