使用 API 网关 cURL 请求触发 Lambda 函数时解析 JSON 正文

Parsing JSON body when triggering a Lambda function with API Gateway cURL request

我正在 运行在 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 网关触发器,但无论我尝试什么 - 我都无法将上述参数正确传递到事件中,就像我 运行 Lambda 测试时一样。

events 通过 API 网关有 different format, and you can't change that for proxy lambda integration. For non-proxy, you can use mapping templates.

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

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

我花了好几个小时胡思乱想,但我想通了。

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

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

{
  "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,这样我就可以在 Lambda 中使用原始 JSON 结构继续 运行ning 测试。

所以我创建了这段代码:

# 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
    }