Python 使用API网关处理AWS Lambda错误

Python 使用API网关处理AWS Lambda错误,python,amazon-web-services,aws-lambda,aws-api-gateway,aws-step-functions,Python,Amazon Web Services,Aws Lambda,Aws Api Gateway,Aws Step Functions,我在Lambda函数中有类BadRequest(异常):pass 我想提出BadRequest(“无效的请求参数”),并让API返回一个状态代码为400、正文为{“message”:“无效的请求参数”}(或等效内容)的响应 但是,简单地这样做会返回一个状态代码为200(哦,不!)和body的响应 { “errorMessage”:“无效的请求参数”, “errorType”:“BadRequest”, “stackTrace”: } 在网上搜索之后,我似乎有3个选择: (一) 2) 使用集成响

我在Lambda函数中有
类BadRequest(异常):pass

我想
提出BadRequest(“无效的请求参数”)
,并让API返回一个状态代码为400、正文为
{“message”:“无效的请求参数”}
(或等效内容)的响应

但是,简单地这样做会返回一个状态代码为200(哦,不!)和body的响应

{
“errorMessage”:“无效的请求参数”,
“errorType”:“BadRequest”,
“stackTrace”:
}
在网上搜索之后,我似乎有3个选择:

(一)

2) 使用集成响应和方法响应将错误解析为更好的响应。我希望正则表达式
[BadRequest]..
并在抛出异常时插入前缀(在我看来不是很优雅)

3) 用于创建API的有状态表示。这似乎有点乏味,因为我需要学习ASL,而且我不认识任何聋人。-

-.-



我应该进入哪个兔子洞?为什么?

您应该捕获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"
}
public类LambdaFunctionHandler实现RequestHandler{
@凌驾
公共字符串handleRequest(字符串输入,上下文){
Map errorPayload=newhashmap();
errorPayload.put(“errorType”、“BadRequest”);
errorPayload.put(“httpStatus”,400);
errorPayload.put(“requestId”,context.getAwsRequestId());
errorPayload.put(“消息”,“无效请求参数”+stackstace);
字符串消息=新的ObjectMapper().writeValueAsString(errorPayload);
抛出新的运行时异常(消息);
}
}
然后使用选项2映射错误代码。
整合响应:
选择模式:“%BadRequest”。*
方法应答:500
映射模板:
#set($errorMessageObj=$util.parseJson($input.path('$.errorMessage')))
{
“类型”:“$errorMessageObj.errorType”,
“消息”:“$errorMessageObj.message”,
“请求id”:“$errorMessageObj.requestId”
}

这是AWS Step函数的完美用例。您需要设置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函数输出的任何内容

希望这有帮助

使使用Lambda和API网关实现restapi变得非常简单,包括将引发的异常转换为响应。对于您的特定情况,您会提出如下异常:

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网关的工作示例:。

三年后,我将回到这个问题上来,描述我今天如何解决这个问题。我使用部署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很容易返回适当的错误消息和错误。我在这个
handle_exceptions
实现中有非常基本的日志记录,但是您可以通过
f.\uuuu name_uuu
获得非常详细的消息,以了解Lambda函数出错的原因以及异常的来源。所有这些错误管理都对API用户完全隐藏。

对chalice和step函数了解不多。我建议对该lambda使用集成响应和方法响应。它是为处理这类问题而构建的功能,我在任何地方都使用它来根据某些触发器格式化我的响应。走这条路线的主要原因是AWS支持解决AWS服务的这个问题。因此,对于您或将来接管此项目的人来说,管理开销更少。另外,这并不难学,然后你也可以为传入的数据编写json语法文档。在这种情况下,如何避免200/回溯响应?另请参阅以下博文:[Amazon API Gateway和AWS Lambda中的错误处理模式]()
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.")