AWS SNS 始终将重复的消息发布到平台应用程序端点

AWS SNS always publish duplicate messages to Platform Applications Endpoint

当从 AWS Lambda 同时向 Apple Push Notifications 发布多条消息时,我发现 AWS SNS 有一个奇怪的行为 - 每条发布的消息都会被订阅者接收两次。

我的代码如下

handler.js

const uuid = require('uuid')
const aws = require('aws-sdk');
const sns = new aws.SNS({ apiVersion: '2010-03-31' })

const messageSender = async (event, context, callback) => {

  // sending 3 messages one after another
  publishMessage("title1", "message1")
  publishMessage("title2", "message2")
  publishMessage("title3", "message3")

  return []
}

const publishMessage = (title, message) => {

  sns.publish({
    Message: JSON.stringify({
      "default": "default message",
      "APNS_SANDBOX": JSON.stringify({
        "aps": {
          "alert": {
            "title": title,
            "body": message
          },
          "badge": 1,
          "id": uuid.v4(),
          "foo": "bar"
        }
      })
    }),
    MessageStructure: 'json',
    TopicArn: process.env.TOPIC_ARN
  }).promise()

  console.log(`Message for topic is published: ${message}`)
}

但是,如果我只发布一条如下所示的消息,则只会收到一次确切的消息。

const messageSender = async (event, context, callback) => {

  publishMessage("title1", "message1")

  return []
}

知道为什么在发送多条消息时会收到两次相同的消息吗?

编辑

玩发布 API 一段时间后,我发现了以下内容。

重复是由潜在的 Amazon SNS 错误(?)引起的。如果不发送 JSON 格式,重复错误就会消失。例如删除 MessageStructure: 'json' 并将消息更改为仅字符串,如下所示。

sns.publish({
    Message: "this is a sample message",
    TopicArn: process.env.TOPIC_ARN
}).promise()

这是该问题的解决方法,但原始问题的根本原因仍然未知。

解决方法有缺点,因为它无法使用 APN 属性自定义通知,例如向推送通知添加标题和徽章。

任何其他解决方法或谁知道修复方法?

经过几个小时的摸索,我终于找到了问题所在。

我在 json 消息中添加了一个自定义的 id 字段,导致在同时发布多条消息时,同一消息被发送两次。

去掉id字段后,无论同时发布多少条消息,消息只发送一次

{
  "default": "default message",
  "APNS_SANDBOX": JSON.stringify({
    "aps": {
      "alert": {
        "title": title,
        "body": message
      },
      "badge": 1,
      // "id": uuid.v4(),  <---- THIS LINE IS REMOVED
      "foo": "bar"
    }
  })
}

ps。我还注意到如果id仍然存在,当以超过3秒的间隔发布消息时,相同的消息被发送一次。

我遇到了同样的问题,但上面的方法没有帮助。

就我而言,我追踪到使用回调函数和 .promise() 方法。

即我有类似的东西:

await SNS.publish({
    TopicArn: process.env.SNS_TOPIC,
    Message: message,
    MessageAttributes: {
        source: {DataType: 'String', StringValue: source},
        level: {DataType: 'String', StringValue: level}
    },
}, function(err, data) {
    if (err) {
        console.log('SNS_notify: error -', err);
    } else {
        console.log('SNS_notify: sent -', data.MessageId);
    }
).promise();

将其更改为:

let data = await SNS.publish({
    TopicArn: process.env.SNS_TOPIC,
    Message: message,
    MessageAttributes: {
        source: {DataType: 'String', StringValue: source},
        level: {DataType: 'String', StringValue: level}
    },
}).promise();

console.log('SNS_notify: sent -', data.MessageId);

已解决问题。