首页 > 解决方案 > AWS API 网关 Datestamp 不是 JSON 可序列化的

问题描述

我正在使用 lambda 函数并使用 API 网关 rest api 触发它。在测试时,我收到以下错误。我需要Datestamp在作为输入的请求正文中传递

我用谷歌搜索并找到了这个链接并尝试了这个解决方案,但它没有用 - https://code-maven.com/serialize-datetime-object-as-json-in-python

我的 index.py -

dynamodb = boto3.resource('dynamodb')
resultstablename=('%s-%s-results' % (Project, Environment))
resultstable = dynamodb.Table(resultstablename)


def lambda_handler(event, context):
    try:
        result = []
        queryresponse = resultstable.scan()
        for i in queryresponse['Items']:
            result.append(i['reports'])

        block=['{"type": "section","text": {"type": "mrkdwn","text": "*Found below reports using Datestamp provided*"}}']
        for item in result:
            print(item)
            print(event['Datestamp'])
            if item.find(event['Datestamp']) != -1:
                itema='{"type": "section","text": {"type": "mrkdwn","text": "<https://%s/%s/%s/index.html|%s>"}}' % (SiteSpeedURL,SiteSpeedPreFix,item,item)
                block.append(itema)

block=('[{}]'.format(', '.join(block)))
        
        url = "%s" % (SlackURL)           
        msg = {
        "channel": "%s" % (ChannelName),
        "username": "%s" % (Username),
        "icon_emoji": ":robot_face:",
        "blocks": "%s" % (block),
            }
        encoded_msg = json.dumps(msg).encode('utf-8')
        **resp = http.request('POST',url, body=encoded_msg)**
        
        return("200")

当我像这样将命令发送到聊天机器人时,相同的代码可以正常工作 -

lambda invoke --function-name monitoring-chatbot-shashank --payload {“Datestamp”:“2020-12-23"}

但是,当我从 API 网关调用此函数时在请求正文中使用时,像这样的相同有效负载会引发错误。

使用休息端点使用 API 网关调用时出现错误 -

Wed Jan 06 11:47:05 UTC 2021 : Lambda execution failed with status 200 due to customer function error: Unable to marshal response: KeyError('Datestamp') is not JSON serializable. Lambda request id: 8baea1a2-517a-4f69-8a8f-6f17746dd360
Wed Jan 06 11:47:05 UTC 2021 : Method completed with status: 502

我不知道还能做什么。如果有人对此有任何想法,请告诉我。

标签: pythonjsonamazon-web-servicesaws-lambdaamazon-dynamodb

解决方案


您的问题是您希望event成为请求主体,但事实并非如此。而不是您通过 CLI 传递的对象,

event == {"Datestamp": "2020-12-23"}

您实际上将获得由 API 网关生成的描述请求的对象(请参阅文档),其中包括作为字符串的请求正文。

event == {
    "resource": "/",
    "path": "/",
    "httpMethod": "GET",
    "requestContext": {
        "resourcePath": "/",
        "httpMethod": "GET",
        "path": "/Prod/",
        ...
    },
    "headers": {
        "accept": "text/html",
        ...
    },
    "multiValueHeaders": {
        ...
    },
    "queryStringParameters": null,
    "multiValueQueryStringParameters": null,
    "pathParameters": null,
    "stageVariables": null,
    "body": "{\"Datestamp\": \"2020-12-23\"}",
    "isBase64Encoded": false
}

因此,要将 JSON 主体作为 Python 字典获取,请尝试以下操作:

body = json.loads(event["body"])

...

if item.find(body['Datestamp']) != -1:
    ...

正如前面的答案所示,“不可序列化 JSON”位是指在事件中不存在KeyError时引发的位"Datestamp"。如您所见,API 网关会将失败的 Lambda 执行(例如,来自未捕获的异常)视为网关错误并返回 502。这可能没问题,但如果您想返回不同的错误(和/或记录更多信息),那么将所有代码包装在 try/except 块中会很有帮助。我还经常喜欢在每个函数的开头打印整个事件,以帮助调试 HTTP 位。

def handler(event, context):
    try:
        print(event)  # helps debug input, not for production
        
        # main app code
        ...
    except Exception as e:
        print(repr(e))  # helps debug other issues, not for production

        return {
            "statusCode": 500,
            "body": "Internal server error: " + repr(e),  # DEFINITELY not for production
        }

确保仅在调试时执行此操作 - 当您打印这些内容时,任何有权访问您的日志的人都可以获得有关应用程序状态的信息,其中可能包括敏感数据,并且当您将其包含在 HTTP 响应中时,任何有权访问您的 API 的人都可以获取可以做同样的事情。


推荐阅读