amazon-web-services - 从 SNS 主题订阅时出现错误的 SQS AWS 消息

标签 amazon-web-services aws-lambda amazon-sqs amazon-sns

我在下一个设计中遇到了问题:

enter image description here

当我在我的 SQS 订阅者中接收消息时,消息的模型是错误的,例如:

{
  "Type" : "Notification",
  "MessageId" : "7a6789f0-02f0-5ed3-8a11-deebcd08f145",
  "TopicArn" : "arn:aws:sns:us-east-2:167186109795:name_sns_topic",
  "Message" : "My JSON message",
  "Timestamp" : "1987-04-23T17:17:44.897Z",
  "SignatureVersion" : "1",
  "Signature" : "string",
  "SigningCertURL" : "url",
  "UnsubscribeURL" : "url",
  "MessageAttributes" : {
    "X-Header1" : {"Type":"String","Value":"value1"},
    "X-Header2" : {"Type":"String","Value":"value2"},
    "X-Header3" : {"Type":"String","Value":"value3"},
    "X-HeaderN" : {"Type":"String","Value":"value4"}
  }
}

从SQS接收消息的常用模型应该是:

{
  "Records": [
    {
      "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
      "receiptHandle": "MessageReceiptHandle",
      "body": "Hello from SQS!",
      "attributes": {
        "ApproximateReceiveCount": "1",
        "SentTimestamp": "1523232000000",
        "SenderId": "123456789012",
        "ApproximateFirstReceiveTimestamp": "1523232000001"
      },
      "messageAttributes": {},
      "md5OfBody": "7b270e59b47ff90a553787216d55d91d",
      "eventSource": "aws:sqs",
      "eventSourceARN": "arn:{partition}:sqs:{region}:123456789012:MyQueue",
      "awsRegion": "{region}"
    }
  ]
}

在我的处理程序中,Java Lambda(示例代码)抛出异常,因为接收到的消息的结构不是 SQS 事件:

public class MyHandler implements RequestHandler<SQSEvent, String> {

  @Override
  public String handleRequest(SQSEvent event, Context context) {
    LambdaLogger logger = context.getLogger();

    for (SQSEvent.SQSMessage msg : event.getRecords()) {
      logger.log("SQS message body: " + msg.getBody());
      logger.log("Get attributes: " + msg.getMessageAttributes().toString());

      msg.getMessageAttributes()
              .forEach(
                      (k, v) -> {
                        logger.log("key: " + k + "value: " + v.getStringValue());
                      });
    }
    return "Successful";
  }
}

How can I do for handle the message thats its receiving ?

最佳答案

在我看来,这并没有得到很好的记录,但一旦你弄明白了,它也不错。

第一件事是我不使用预定义的 Lambda 对象。我将所有内容读入一个字符串并从那里获取。所以我的 Lamda 函数的基础是:

public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
    // copy InputStream to String, avoiding 3rd party libraries
    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer)) != -1) {
        result.write(buffer, 0, length);
    }

    String jsonString = result.toString();
}

当您从 SNS“直接”到 Lambda 时,消息看起来像这样(为了长度而删除了一些字段):

{
    "Records": [
        {
            "EventSource": "aws:sns",
            "EventVersion": "1.0",
            "Sns": {
                "Type": "Notification",
                "Subject": "the message subject",
                "Message": "{\"message\": \"this is the message\", \"value\": 100}",
                "Timestamp": "2020-04-24T21:44:28.220Z",
                "SignatureVersion": "1"
            }
        }
    ]
}

我发送了一条包含两个简单字段的 JSON 格式的测试消息。使用 JsonPath读取所有内容中的“消息”字段:

String snsMessage = JsonPath.read(jsonString, "$.Records[0].Sns.Message");
String realMessage = JsonPath.read(snsMessage, "$.message");

但是当它进入 SNS -> SQS -> Lambda(或者实际上任何 SNS -> SQS 路径)时,SNS 消息现在大部分被包装并在 SQS 消息中转义:

{
    "Records": [
        {
            "messageId": "ca8c53e5-8417-4479-a720-d4ecf970ca68",
            "body": "{\n  \"Type\" : \"Notification\",\n  \"Subject\" : \"the message subject\",\n  \"Message\" : \"{\\\"message\\\": \\\"this is the message\\\", \\\"value\\\": 100}\"\n}",
            "attributes": {
                "ApproximateReceiveCount": "1"
            },
            "md5OfBody": "6a4840230aca6a7bf7934bf191a529b8",
            "eventSource": "aws:sqs"
        }
    ]
}

所以在这种情况下,该值位于 Records[0].body 中,但它包含另一个 JSON 对象。我承认可能有更简单的方法,但从我发现的情况来看,我必须解析 3 次:

String sqsBody = <as read in lambda>;
String recordBody = JsonPath.read(sqsBody, "$.Records[0].body");
String internalMessage = JsonPath.read(recordBody, "$.Message");
// now read out of the sns message
String theSnsMessage = JsonPath.read(message, "$.message");

关于amazon-web-services - 从 SNS 主题订阅时出现错误的 SQS AWS 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61410478/

相关文章:

node.js - AWS Lambda 上的 NodeJS 集群

node.js - SQS 到 Lambda + SES

java - 有没有办法监控SES等指定AWS服务的健康状态?

amazon-web-services - Amazon CloudWatch Logs 是否支持换行符?

mysql - 通过 SSH 隧道的 Flyway

mysql - AWS Lambda 和 RDS 工作示例(需要它与 Sequelize 一起使用)

.net - Lambda AWS 即时返回日志

amazon-web-services - 云信息 : prevent deletion after updates on replacement resources

java - 如何在单元测试中模拟 AmazonSQS 而不调用 SQS?

amazon-web-services - AWS SQS 可以发布到 SNS 还是需要轮询 SQS?