【问题标题】:Parsing JSON body when triggering a Lambda function with API Gateway cURL request使用 API Gateway cURL 请求触发 Lambda 函数时解析 JSON 正文
【发布时间】:2022-01-09 07:55:20
【问题描述】:

我正在 AWS Lambda 上运行一个通过 SMTP 发送电子邮件的简单函数。

该函数使用来自event 的各种参数,例如"event["reply_to_msg_id"]" 和"event["sender_name"]"。

import smtplib
from email.message import EmailMessage
from email.utils import make_msgid

def lambda_handler(event, context):
    msg = EmailMessage()
    if event["reply_to_msg_id"] != "":
        msg['References'] = event["reply_to_msg_id"]
        msg['In-Reply-To'] = event["reply_to_msg_id"]
        msg['subject'] = "Re: " + event["content"]["Subject Line"]
    else:
        msg['subject'] = event["content"]["Subject Line"]
    msg['from'] = event["sender_name"]
    msg['To'] = event["target_email"]
    msg['Message-ID'] = make_msgid('random_client_id')
    msg.add_header('Content-Type', 'text/html')
    msg.set_payload(event["content"]["Body"])
    server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
    result = {"Message-ID": msg['Message-ID']}
    try:
        server.login(event["email_account"]["email_address"], event["email_account"]["password"])
        server.send_message(msg)
        server.quit()
        result["Status"] = "Success"

    except Exception as E:
        result["Status"] = str(E)

    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
        },
        'body': json.dumps(result),
        "isBase64Encoded": False
    }

当我在 AWS Lambda 中使用以下主体运行测试事件时,一切正常:

{
  "reply_to_msg_id": "",
  "content": {
    "Subject Line": "Test subject line.",
    "Body": "This is <b>a body</b>."
  },
  "sender_name": "Joe Peschi",
  "target_email": "test@gmail.com",
  "email_account": {
    "email_address": "***********",
    "password": "***********"
  }
}

问题:

我不知道如何使用 API 网关实际重现此内容。我为此函数创建了一个 API Gateway 触发器,但无论我尝试什么 - 我都无法正确地将上述参数传递给事件,就像我运行 Lambda 测试时一样。

【问题讨论】:

    标签: amazon-web-services aws-lambda aws-api-gateway


    【解决方案1】:

    events 通过 API 网关有 different format,你不能为代理 lambda 集成更改它。对于非代理,您可以使用mapping templates

    验证event 结构的最佳方法是将其打印出来并检查,如果您不使用映射模板,则在需要时修改 lambda 代码:

    print(json.dumps(event, default=str))
    

    【讨论】:

    • 对此不是 100% 确定的。您可以使用 API Gateway 中的映射模板来“规范化”输入。这样,您可以在不同的上下文中使用相同的 Lambda(通过 API Gateway、Step Functions、curl 等调用)还是我在这里遗漏了什么?
    • @Jens Op 不提供有关模板使用的任何信息。但是,是的,你是对的。我会更新答案。谢谢。
    • 我猜 OP 没有包括它们,因为大多数人都不知道它们。为了简单起见,所有教程或多或少都使用代理集成,因此这是大多数人不知道的功能之一。感谢您花时间更新您的答案:)
    • 感谢您的回答。它帮助我找到了不需要更改函数或测试 JSON 的解决方案。我发布了我的解决方案作为答案。
    【解决方案2】:

    花了我几个小时搞砸了,但我想通了。

    json_body = json.loads(json.loads(json.dumps(event, default=str))["body"])
    

    使用上面的代码,我可以发送这个 JSON 正文并将其转换为 dict 变量:

    {
      "reply_to_msg_id": "",
      "content": {
        "Subject Line": "Test subject line.",
        "Body": "This is <b>a body</b>."
      },
      "sender_name": "Joe Peschi",
      "target_email": "test@gmail.com",
      "email_account": {
        "email_address": "***********",
        "password": "***********"
      }
    }
    

    但是,我还想继续使用event,这样我就可以继续使用原始 JSON 结构在 Lambda 中运行测试。

    所以我创建了这段代码:

    # THIS LINE TAKES THE REQUEST'S JSON BODY, AND TURNS IT INTO A DICT:
    try:
        json_body = json.loads(json.loads(json.dumps(event, default=str))["body"])
    except:
        json_body = ""
    
    if json_body != "":
        event = json_body
    

    现在我可以运行 cURL 请求,它会完美运行:

    curl --location --request GET 'https://********.execute-api.us-east-2.amazonaws.com/default/send_email_via_smtp' \
    --header 'x-api-key: ****************' \
    --header 'Content-Type: text/plain' \
    --data-raw '{
      "reply_to_msg_id": "",
      "content": {
        "Subject Line": "Test subject line.",
        "Body": "This is <b>a body</b>."
      },
      "sender_name": "Joe Peschi",
      "target_email": "robbyqla@gmail.com",
      "email_account": {
        "email_address": "**********",
        "password": "********"
      }
    }'
    

    但是我也可以使用原始的 JSON 结构通过 Lambda 测试运行一个请求,它也可以完美运行:

    这是最终代码:

    import smtplib
    from email.message import EmailMessage
    from email.utils import make_msgid
    
    def lambda_handler(event, context):
    
        try:
            json_body = json.loads(json.loads(json.dumps(event, default=str))["body"])
        except:
            json_body = ""
    
        if json_body != "":
            event = json_body
    
        msg = EmailMessage()
        if event["reply_to_msg_id"] != "":
            msg['References'] = event["reply_to_msg_id"]
            msg['In-Reply-To'] = event["reply_to_msg_id"]
            msg['subject'] = "Re: " + event["content"]["Subject Line"]
        else:
            msg['subject'] = event["content"]["Subject Line"]
        msg['from'] = event["sender_name"]
        msg['To'] = event["target_email"]
        msg['Message-ID'] = make_msgid('random_client_id')
        msg.add_header('Content-Type', 'text/html')
        msg.set_payload(event["content"]["Body"])
        server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
        result = {"Message-ID": msg['Message-ID']}
        try:
            server.login(event["email_account"]["email_address"], event["email_account"]["password"])
            server.send_message(msg)
            server.quit()
            result["Status"] = "Success"
    
        except Exception as E:
            result["Status"] = str(E)
    
        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*'
            },
            'body': json.dumps(result),
            "isBase64Encoded": False
        }
    

    【讨论】:

      猜你喜欢
      • 2016-02-07
      • 2021-10-24
      • 2016-01-30
      • 1970-01-01
      • 2020-04-16
      • 2016-03-16
      • 2017-04-24
      • 2023-02-14
      • 2017-11-13
      相关资源
      最近更新 更多