格式错误的Lambda代理响应:字符串索引必须是整数

时间:2017-06-24 16:16:38

标签: python aws-lambda aws-api-gateway serverless-framework

我正在尝试使用AWS Lambda为应用程序编写无服务器后端,并且遇到了标题中的错误。使用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

基本上代理集成似乎是在事件对象中读取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__))"
      ]
   ]
}

我无法获胜。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:4)

您已确定此问题。但是,您尝试将dict转换为dict

这就是你所拥有的:

json.loads(event) # event is a dict

您正确识别的身体部位是str

这就是你应该拥有的:

json.loads(event['body'])

另一个步骤是使其与客户端无关。

if isinstance(event['body'], (unicode, str)):
    body = json.loads(event['body'])

答案 1 :(得分:2)

这是因为event['body']不是dict而是str。 (解码SQS触发事件时遇到了这个问题)

如果有人再次遇到问题,而json.loads(event['body'])的值再次不是dict而是str时,这是一种将str递归解码的解决方案。

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”。

答案 2 :(得分:1)

在处理json时,python提供了2个std函数:

https://docs.python.org/3/library/json.html#json.dumps

  

使用此转换表将obj序列化为JSON格式的str。该   参数与dump()中的含义相同。

https://docs.python.org/3/library/json.html#json.loads

  

反序列化s(包含JSON的str,bytes或bytearray实例   文档)使用此转换表的Python对象。

这里你需要的是最新的:

import json
payload = json.loads(event['body']

event['body']可能是一个json str,所以为了访问它的值,你需要通过`json.loads

将它转换为python obj