格式错误的 Lambda 代理响应:字符串索引必须是整数
Malformed Lambda proxy response: string indices must be integers
我正在尝试使用 AWS Lambda 为应用程序编写无服务器 back-end,并且 运行 进入了标题中的错误。使用 API 网关代理集成进行测试时会出现此错误,但在 Lambda 控制台中测试时该功能可以正常工作。
这里是错误:
{
"errorMessage":"string indices must be integers",
"errorType":"TypeError",
"stackTrace":[
[
"/var/task/auth_login.py",
17,
"lambda_handler",
"response = get_user(payload)"
],
[
"/var/task/shifty_utils/__init__.py",
22,
"get_user",
"table = dynamo.Table(user['company'] + '_users')"
]
]
}
这是它发生的地方的上下文:
def lambda_handler(event, context):
payload = event['body']
response = get_user(payload)
def get_user(user):
try:
table = dynamo.Table(user['company'] + '_users')
response = table.get_item(
Key={
'userId': user['userId'],
'position': user['position']
}
)
except ClientError as e:
print(e.response['Error']['Message'])
return {'message': e.response['Error']['Message']}
else:
return response
基本上代理集成似乎在事件 object 中读取为 JSON 格式的字符串,而不是字典,但是如果我为此调整代码会发生以下情况:
{
"errorMessage":"the JSON object must be str, bytes or bytearray, not 'dict'",
"errorType":"TypeError",
"stackTrace":[
[
"/var/task/auth_login.py",
15,
"lambda_handler",
"payload = json.loads(event)"
],
[
"/var/lang/lib/python3.6/json/__init__.py",
348,
"loads",
"'not {!r}'.format(s.__class__.__name__))"
]
]
}
我赢不了。感谢任何帮助。
您已确定问题所在。但是,您正在尝试将 dict
转换为 dict
。
这是你拥有的:
json.loads(event) # event is a dict
您正确识别的 body 部分是作为 str
进入的部分。
这是你应该拥有的:
json.loads(event['body'])
还有一个步骤就是client-agnostic。
if isinstance(event['body'], (unicode, str)):
body = json.loads(event['body'])
处理json时,python提供2个std函数:
https://docs.python.org/3/library/json.html#json.dumps
Serialize obj to a JSON formatted str using this conversion table. The
arguments have the same meaning as in dump().
https://docs.python.org/3/library/json.html#json.loads
Deserialize s (a str, bytes or bytearray instance containing a JSON
document) to a Python object using this conversion table.
这里需要的是最新的:
import json
payload = json.loads(event['body']
event['body']
可能是一个 json str 所以要访问它的值,你需要先通过`json.loads[= 将它转换为 python obj 16=]
这是因为 event['body']
不是 dict
,而是 str
。 (我在解码 SQS 触发事件时 运行 遇到了这个问题)
万一有人 运行 在 json.loads(event['body'])
的值再次不是 dict
而是 str
时遇到问题,这里有一个将 str 解码为 dict 的解决方案递归地。
import json
def to_dict(obj : object) -> dict:
""" Serialize Object to Dictionary Recursively
Arguments:
obj {object} -- string, list, or dictionary to be serialize
Returns:
dict -- Serialized Dictionary
"""
if isinstance(obj, dict):
data = {}
for k, v in obj.items():
data[k] = to_dict(v)
return data
elif hasattr(obj, "_ast"):
return to_dict(obj._ast())
elif hasattr(obj, "__iter__") and not isinstance(obj, str):
return [to_dict(v) for v in obj]
elif hasattr(obj, "__dict__"):
data = {key : to_dict(value) for key, value in obj.__dict__.items() if
not callable(value) and not key.startswith('_')}
elif isinstance(obj, str):
try:
data = {}
obj = json.loads(obj)
for k, v in obj.items():
data[k] = to_dict(v)
return data
except:
return obj
else:
return obj
用法示例:
test = {'Records': ['{"s3": "{\"bucket\": \"bucketname\"}"}', '{"s3": "{\"bucket\": \"bucketname\"}"}']}
print(to_dict(test)['Records'][0]['s3']['bucket'])
这应该打印 "bucketname".
我正在尝试使用 AWS Lambda 为应用程序编写无服务器 back-end,并且 运行 进入了标题中的错误。使用 API 网关代理集成进行测试时会出现此错误,但在 Lambda 控制台中测试时该功能可以正常工作。
这里是错误:
{
"errorMessage":"string indices must be integers",
"errorType":"TypeError",
"stackTrace":[
[
"/var/task/auth_login.py",
17,
"lambda_handler",
"response = get_user(payload)"
],
[
"/var/task/shifty_utils/__init__.py",
22,
"get_user",
"table = dynamo.Table(user['company'] + '_users')"
]
]
}
这是它发生的地方的上下文:
def lambda_handler(event, context):
payload = event['body']
response = get_user(payload)
def get_user(user):
try:
table = dynamo.Table(user['company'] + '_users')
response = table.get_item(
Key={
'userId': user['userId'],
'position': user['position']
}
)
except ClientError as e:
print(e.response['Error']['Message'])
return {'message': e.response['Error']['Message']}
else:
return response
基本上代理集成似乎在事件 object 中读取为 JSON 格式的字符串,而不是字典,但是如果我为此调整代码会发生以下情况:
{
"errorMessage":"the JSON object must be str, bytes or bytearray, not 'dict'",
"errorType":"TypeError",
"stackTrace":[
[
"/var/task/auth_login.py",
15,
"lambda_handler",
"payload = json.loads(event)"
],
[
"/var/lang/lib/python3.6/json/__init__.py",
348,
"loads",
"'not {!r}'.format(s.__class__.__name__))"
]
]
}
我赢不了。感谢任何帮助。
您已确定问题所在。但是,您正在尝试将 dict
转换为 dict
。
这是你拥有的:
json.loads(event) # event is a dict
您正确识别的 body 部分是作为 str
进入的部分。
这是你应该拥有的:
json.loads(event['body'])
还有一个步骤就是client-agnostic。
if isinstance(event['body'], (unicode, str)):
body = json.loads(event['body'])
处理json时,python提供2个std函数:
https://docs.python.org/3/library/json.html#json.dumps
Serialize obj to a JSON formatted str using this conversion table. The arguments have the same meaning as in dump().
https://docs.python.org/3/library/json.html#json.loads
Deserialize s (a str, bytes or bytearray instance containing a JSON document) to a Python object using this conversion table.
这里需要的是最新的:
import json
payload = json.loads(event['body']
event['body']
可能是一个 json str 所以要访问它的值,你需要先通过`json.loads[= 将它转换为 python obj 16=]
这是因为 event['body']
不是 dict
,而是 str
。 (我在解码 SQS 触发事件时 运行 遇到了这个问题)
万一有人 运行 在 json.loads(event['body'])
的值再次不是 dict
而是 str
时遇到问题,这里有一个将 str 解码为 dict 的解决方案递归地。
import json
def to_dict(obj : object) -> dict:
""" Serialize Object to Dictionary Recursively
Arguments:
obj {object} -- string, list, or dictionary to be serialize
Returns:
dict -- Serialized Dictionary
"""
if isinstance(obj, dict):
data = {}
for k, v in obj.items():
data[k] = to_dict(v)
return data
elif hasattr(obj, "_ast"):
return to_dict(obj._ast())
elif hasattr(obj, "__iter__") and not isinstance(obj, str):
return [to_dict(v) for v in obj]
elif hasattr(obj, "__dict__"):
data = {key : to_dict(value) for key, value in obj.__dict__.items() if
not callable(value) and not key.startswith('_')}
elif isinstance(obj, str):
try:
data = {}
obj = json.loads(obj)
for k, v in obj.items():
data[k] = to_dict(v)
return data
except:
return obj
else:
return obj
用法示例:
test = {'Records': ['{"s3": "{\"bucket\": \"bucketname\"}"}', '{"s3": "{\"bucket\": \"bucketname\"}"}']}
print(to_dict(test)['Records'][0]['s3']['bucket'])
这应该打印 "bucketname".