【问题标题】:Malformed Lambda proxy response: string indices must be integers格式错误的 Lambda 代理响应:字符串索引必须是整数
【发布时间】:2017-11-28 00:53:16
【问题描述】:

我正在尝试使用 AWS Lambda 为应用程序编写无服务器后端,但遇到了标题中的错误。使用 API Gateway 代理集成进行测试时会出现错误,但在 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 格式的字符串读取,而不是 dict,但如果我为此调整代码会发生以下情况:

{  
   "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__))"
      ]
   ]
}

我赢不了。任何帮助表示赞赏。

【问题讨论】:

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


    【解决方案1】:

    您已确定问题所在。但是,您正在尝试将 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'])
    

    【讨论】:

      【解决方案2】:

      在处理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 实例 document) 使用此转换表转换为 Python 对象。

      你需要的是最新的:

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

      event['body'] 可能是一个 json str,因此要访问它的值,您需要先通过 `json.loads 将其转换为 python obj

      【讨论】:

        【解决方案3】:

        这是因为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”。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-30
          • 2012-12-11
          • 2021-10-30
          • 2021-09-20
          • 2021-09-07
          • 2020-06-18
          相关资源
          最近更新 更多