Ala*_*ack 15 python exception-handling aws-lambda aws-api-gateway
我在非代理模式下从API网关调用基于Python的AWS Lambda方法.我应该如何正确处理异常,以便使用部分异常设置适当的HTTP状态代码和JSON主体.
作为一个例子,我有以下处理程序:
def my_handler(event, context):
try:
s3conn.head_object(Bucket='my_bucket', Key='my_filename')
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "404":
raise ClientException("Key '{}' not found".format(filename))
# or: return "Key '{}' not found".format(filename) ?
class ClientException(Exception):
pass
Run Code Online (Sandbox Code Playgroud)
我应该抛出异常还是返回一个字符串?那我该如何配置集成响应?显然我有RTFM,但FM是FU.
Ala*_*ack 30
关于Lambda,API Gateway以及它们如何协同工作,您需要了解许多内容.
从处理程序/函数/方法抛出异常时,异常将序列化为JSON消息.从您的示例代码,在S3的404上,您的代码将抛出:
{
"stackTrace": [
[
"/var/task/mycode.py",
118,
"my_handler",
"raise ClientException(\"Key '{}' not found \".format(filename))"
]
],
"errorType": "ClientException",
"errorMessage": "Key 'my_filename' not found"
}
Run Code Online (Sandbox Code Playgroud)
"集成响应"将响应从Lambda映射到HTTP代码.它们还允许消息体在通过时进行更改.
默认情况下,为您配置"200"集成响应,它将Lambda的所有响应按原样传递回客户端,包括序列化的JSON异常,作为HTTP 200(OK)响应.
对于好消息,您可能希望使用"200"集成响应将JSON有效负载映射到您定义的模型之一.
对于例外,您需要设置适当的HTTP状态代码,并可能删除堆栈跟踪以隐藏代码的内部.
对于您希望返回的每个HTTP状态代码,您需要添加"集成响应"条目.集成响应配置了与errorMessage字段匹配的正则表达式匹配(使用java.util.regex.Matcher.matches()
not .find()
).完成匹配后,您可以配置正文映射模板,以选择性地格式化合适的异常体.
由于正则表达式仅匹配异常中的errorMessage字段,因此您需要确保您的异常包含足够的信息以允许不同的Integration响应匹配并相应地设置错误.(您不能.*
用来匹配所有异常,因为它似乎匹配所有响应,包括非例外!)
要在消息中创建具有足够详细信息的异常,错误处理模式在amazon-api-gateway-and-aws-lambda博客中建议您在处理程序中创建异常处理程序,以将异常的详细信息填充到JSON中要在异常消息中使用的字符串.
我首选的方法是创建一个新的top方法作为处理程序,处理响应API网关.此方法返回所需的有效负载,或者将编译为JSON字符串的原始异常作为异常消息抛出异常.
def my_handler_core(event, context):
try:
s3conn.head_object(Bucket='my_bucket', Key='my_filename')
...
return something
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "404":
raise ClientException("Key '{}' not found".format(filename))
def my_handler(event=None, context=None):
try:
token = my_handler_core(event, context)
response = {
"response": token
}
# This is the happy path
return response
except Exception as e:
exception_type = e.__class__.__name__
exception_message = str(e)
api_exception_obj = {
"isError": True,
"type": exception_type,
"message": exception_message
}
# Create a JSON string
api_exception_json = json.dumps(api_exception_obj)
raise LambdaException(api_exception_json)
# Simple exception wrappers
class ClientException(Exception):
pass
class LambdaException(Exception):
pass
Run Code Online (Sandbox Code Playgroud)
在例外情况下,Lambda现在将返回:
{
"stackTrace": [
[
"/var/task/mycode.py",
42,
"my_handler",
"raise LambdaException(api_exception_json)"
]
],
"errorType": "LambdaException",
"errorMessage": "{\"message\": \"Key 'my_filename' not found\", \"type\": \"ClientException\", \"isError\": true}"
}
Run Code Online (Sandbox Code Playgroud)
现在您已经拥有了errorMessage中的所有详细信息,您可以开始映射状态代码并创建格式良好的错误有效负载.API网关解析和取消了errorMessage字段,因此使用的正则表达式不需要处理转义.
例要将此ClientException捕获为400错误并将有效内容映射到干净的错误模型,您可以执行以下操作:
创建新的错误模型:
{
"type": "object",
"title": "MyErrorModel",
"properties": {
"isError": {
"type": "boolean"
},
"message": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"token",
"isError",
"type"
]
}
Run Code Online (Sandbox Code Playgroud)400
400
.*"type"\s*:\s*"ClientException".*
添加一个Body Mapping模板,application/json
用于将内容映射errorMessage
到您的模型:
#set($inputRoot = $input.path('$'))
#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))
{
"isError" : true,
"message" : "$errorMessageObj.message",
"type": "$errorMessageObj.type"
}
Run Code Online (Sandbox Code Playgroud)