【问题标题】:Lambda function receiving null S3 event object via SNSLambda 函数通过 SNS 接收空 S3 事件对象
【发布时间】:2017-07-24 09:08:30
【问题描述】:

我正在尝试使用携带 S3 事件负载的 SNS 事件调用 Lambda 函数(即 S3 Put -> 触发发布到 SNS 主题的事件 -> 传递到订阅的 Lambda 函数),但它似乎是唯一的我能够获得实际 S3 事件信息的方法是将其作为 JsonNode 访问,我知道必须有更好的方法(例如反序列化)。

我真的认为我可以让我的 Lambda 函数接受 S3EventNotification,因为我在这里找到了 cmets:

https://github.com/aws/aws-sdk-java/blob/master/aws-java-sdk-s3/src/main/java/com/amazonaws/services/s3/event/S3EventNotification.java

一个帮助类,表示发送的强类型 S3 EventNotification 项 到 SQS、SNS 或 Lambda。

那么,我如何将 S3EventNotification 作为 POJO 接收?

以下是我尝试过的各种方法:

public class LambdaFunction implements RequestHandler<S3EventNotification, Object>{

    @Override
    public Object handleRequest(S3EventNotification input, Context context) {
        System.out.println(JsonUtil.MAPPER.writeValueAsString(input));       
        return null;
    }
}

导致:

{
    "Records": [
        {
            "awsRegion": null,
            "eventName": null,
            "eventSource": null,
            "eventTime": null,
            "eventVersion": null,
            "requestParameters": null,
            "responseElements": null,
            "s3": null,
            "userIdentity": null
        }
    ]
}

我也尝试了以下方法(注意:JsonUtil.MAPPER 只返回一个 Jackson ObjectMapper):

public class LambdaFunction {
    public Object handleRequest(S3EventNotification records, Context context) throws IOException {
        System.out.println(JsonUtil.MAPPER.writeValueAsString(records));           
        return null;
    }
}

这返回和以前一样:

{
  "Records": [
    {
      "awsRegion": null,
      "eventName": null,
      "eventSource": null,
      "eventTime": null,
      "eventVersion": null,
      "requestParameters": null,
      "responseElements": null,
      "s3": null,
      "userIdentity": null
    }
  ]
}

我可以通过简单地接收 SNSEvent 来访问 S3 事件负载,但是当我尝试将 msg 负载反序列化为 S3EventRecord 或 S3EventNotification 时,字段存在差异。我真的不想手动走下 JsonNode...

public class LambdaFunction {
    public Object handleRequest(SNSEvent input, Context context) throws IOException {
    System.out.println("Records: " + JsonUtil.MAPPER.writeValueAsString(input));

    for (SNSEvent.SNSRecord record : input.getRecords()) {
        System.out.println("Record Direct: " + record.getSNS().getMessage());
        JsonNode node = JsonUtil.MAPPER.readTree(record.getSNS().getMessage());
        JsonNode recordNode = ((ArrayNode) node.get("Records")).get(0);
        System.out.println(recordNode.toString());
        S3EventNotification s3events = JsonUtil.MAPPER.readValue(record.getSNS().getMessage(), new TypeReference<S3EventNotification>() {});
        System.out.println(s3events == null);

    }
    return null;
}

这将返回以下内容:

{
  "eventVersion": "2.0",
  "eventSource": "aws:s3",
  "awsRegion": "us-east-1",
  "eventTime": "2017-03-04T05:34:25.149Z",
  "eventName": "ObjectCreated:Put",
  "userIdentity": {
    "principalId": "AWS:XXXXXXXXXXXXX"
  },
  "requestParameters": {
    "sourceIPAddress": "<<IP ADDRESS>>"
  },
  "responseElements": {
    "x-amz-request-id": "XXXXXXXX",
    "x-amz-id-2": "XXXXXXXXXXXXX="
  },
  "s3": {
    "s3SchemaVersion": "1.0",
    "configurationId": "NotifyNewRawArticle",
    "bucket": {
      "name": "MYBUCKET",
      "ownerIdentity": {
        "principalId": "XXXXXXXXXXXXXXX"
      },
      "arn": "arn:aws:s3:::MYBUCKET"
    },
    "object": {
      "key": "news\/test",
      "size": 0,
      "eTag": "d41d8cd98f00b204e9800998ecf8427e",
      "sequencer": "0058BA51E113A948C3"
    }
  }
}

Unrecognized field "sequencer" (class com.amazonaws.services.s3.event.S3EventNotification$S3ObjectEntity), not marked as ignorable (4 known properties: "size", "versionId", "eTag", "key"])

我依赖 aws-java-sdk-s3-1.11.77 和 aws-java-sdk-sns-1.11.77。

【问题讨论】:

    标签: amazon-web-services amazon-s3 aws-lambda aws-sdk amazon-sns


    【解决方案1】:

    您应该处理 SNSEvent 而不是 S3Event,因为 lambda 会消耗您的 SNS 事件。下面的代码对我有用。

    public Object handleRequest(SNSEvent request, Context context) {
        request.getRecords().forEach(snsRecord -> {
            System.out.println("Record Direct: " +snsRecord.getSNS().getMessage());
            S3EventNotification s3eventNotifcation=S3Event.parseJson(snsRecord.getSNS().getMessage());
            System.out.println(s3eventNotifcation.toJson());
           }
        );
    }
    

    【讨论】:

    • 从打印出 SNSMessage 中可以清楚地看出它拥有一个序列化的 S3Event 对象。无论如何,我试图将它反序列化为 POJO,并且由于它应该与 S3Event 匹配,我认为这应该可以工作,但这不是我上面概述的原因。
    • 你的第一个lambada函数得出结论,实际上我2天前刚刚弄错了。上面的代码对我有用。
    猜你喜欢
    • 2021-05-01
    • 1970-01-01
    • 2021-02-13
    • 2017-12-01
    • 2019-09-15
    • 2018-01-08
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    相关资源
    最近更新 更多