我对下一个设计有疑问:
当我在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(示例代码)引发异常,因为收到的de消息的结构不是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 ?
答案 0 :(得分:0)
在我看来,这没有得到很好的记录,但是一旦弄清楚,还不错。
第一件事是我不使用预定义的Lambda对象。我将所有内容读入String并从那里获取。因此,我的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");