AWS API-шлюз для связи с SNS


Я создаю API, который будет обслуживаться лямбда-функциями, но мне нужно, чтобы они были асинхронными, поэтому вместо подключения API-шлюза непосредственно к функции лямбда я использую "AWS Service Proxy" для публикации сообщений SNS, а затем заставляю функцию Lambda подписаться на соответствующую тему SNS, чтобы она получала доставку запросов. Вот картина, которая иллюстрирует этот поток:

Введите описание изображения здесь

Я проверил обе лямбда-функции изолированно. а также pub/sub обмен сообщениями между SNS и Lambda, но я борюсь с API-шлюзом для передачи SNS. Документация довольно легкая, но сейчас я предполагаю, что в запросе POST должны быть отправлены следующие атрибуты:

  1. Действие : API-шлюз предлагает установить это в UI, и я ввел действие Publish , которое является соответствующим действием SNS

  2. Message : тело сообщения POST должно быть JSON документ. Он будет передан веб-клиентом и проксирован через шлюз в SNS.

  3. TopicArn : указывает тему SNS, которую мы публикуем. В моем дизайне это будет статическое значение / конечная точка, поэтому я предпочел бы, чтобы веб-клиент не должен был передавать это тоже, но если бы это было проще сделать, это тоже было бы прекрасно.

Я перепробовал много вещей, но просто застрял. Хотел бы найти хороший пример кода где-нибудь, но любая помощь вообще будет оцененный.


Хотел добавить немного больше контекста к моей текущей попытке:

Я попытался опубликовать свой API и использовать Postman, чтобы попытаться получить правильный ответ. Вот экраны почтальона(один для заголовка vars, один для тела JSON):

переменные заголовка тело json

Это приводит к следующему сообщению об ошибке:

{
   "Error": {
     "Code": "InvalidParameter",
     "Message": "Invalid parameter: TopicArn or TargetArn Reason: no value for required parameter",
     "Type": "Sender"
  },
  "RequestId": "b33b7700-e8a3-58f7-8ebe-39e4e62b02d0"
}

Ошибка, по-видимому, указывает на то, что параметр TopicArn не отправляется в SNS, но я включил следующее в API-шлюзе:

Введите описание изображения здесь

5 13

5 ответов:

Я из команды Api Gateway.

Я полагаю, что существует несколько форматов для HTTP-запроса к API публикации, но вот тот, который я использовал первым:

Регион AWS us-west-2

Сервис AWS sns

Субдомен AWS

HTTP метод POST

Действие Опубликовать

= = строки запроса = =

Субъект ' foo '
Сообщение ' bar '
TopicArn 'Арн:АРМ:СНС:США-Запад-2:Ремчуков:тест-АФИ'

Это сработало для меня, чтобы опубликовать сообщение.

Дайте мне знать, если у вас возникнут новые проблемы.

Джек

В конце концов я добился, чтобы это сработало после работы с поддержкой AWS. Вот мое решение:

  • Во-первых, даже если вы отправляете POST , Вы не сможете отправить сообщение JSON в теле сообщения, как вы могли бы ожидать
  • вместо этого вы должны кодировать URL-адрес JSON и передавать его в качестве параметра запроса
  • Также помните, что JSON, который вы отправляете, должен начинаться с корневого объекта default , который в SNS-world означает "канал по умолчанию"
  • затем, в конце концов Лямбда улавливает событие SNS вы также должны абстрагироваться от большого количества шума, чтобы добраться до Вашего сообщения JSON. Для этого я создал следующую функцию, которую использую в своей лямбда-функции:

/**
 * When this is run in AWS it is run "through" a SNS
 * event wconfig.ich adds a lot of clutter to the event data,
 * this tests for SNS data and normalizes when necessary
 */
function abstractSNS(e) {
  if (e.Records) {
    return JSON.parse(decodeURIComponent(e.Records[0].Sns.Message)).default;
  } else {
    return e;
  }
}

/**
 * HANDLER
 * This is the entry point for the lambda function
 */
exports.handler = function handler(event, context) {
  parent.event = abstractSNS(event);

Вы можете использовать API Gateway для асинхронного вызова функции Lambda, настроив ее в качестве прокси-сервера сервиса AWS. Конфигурация в основном та же, что вы видите в этом примере GitHub, за исключением того, что uri для лямбда-вызова изменяется на / invoke-async / вместо просто / invoke /

Я просто размышляю (сам этого не пробовал), но я думаю, что вы неправильно посылаете сообщение...

На основе документации AWS здесь (http://docs.aws.amazon.com/sns/latest/api/API_Publish.html ), вам нужно отправить сообщение в том, что кажется кодировкой application/x-www-form-urlencoded следующим образом:

POST http://sns.us-west-2.amazonaws.com/ HTTP/1.1
...
Action=Publish
&Message=%7B%22default%22%3A%22This+is+the+default+Message%22%2C%22APNS_SANDBOX%22%3A%22%7B+%5C%22aps%5C%22+%3A+%7B+%5C%22alert%5C%22+%3A+%5C%22You+have+got+email.%5C%22%2C+%5C%22badge%5C%22+%3A+9%2C%5C%22sound%5C%22+%3A%5C%22default%5C%22%7D%7D%22%7D
&TargetArn=arn%3Aaws%3Asns%3Aus-west-2%3A803981987763%3Aendpoint%2FAPNS_SANDBOX%2Fpushapp%2F98e9ced9-f136-3893-9d60-776547eafebb
&SignatureMethod=HmacSHA256
&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE
&SignatureVersion=2
&Version=2010-03-31
&Signature=vmqc4XRupKAxsDAdN4j4Ayw5LQljXMps3kss4bkDfCk%3D
&Timestamp=2013-07-18T22%3A44%3A09.452Z
&MessageStructure=json

То есть тело сообщения выглядит так, как браузер будет кодировать данные формы. Ваше сообщение может быть отформатировано в формате JSON, но все равно должно быть закодировано, как если бы это было поле формы (an неловкая аналогия :)).

Также на основе документации по общим параметрам (http://docs.aws.amazon.com/sns/latest/api/CommonParameters.html ), у вас есть ряд дополнительных обязательных полей (обычный ключ доступа, подпись и так далее).

Вы не указали, на каком языке вы пишете свой API-шлюз - для него может быть AWS SDK, который вы можете использовать вместо того, чтобы пытаться вручную составлять запросы REST).

Я бы сделал это так:

Веб-приложение --> шлюз --> лямбда ( использовать Boto3 опубликовать в СНС ) --> СНС -->лямда -

Я думаю, все будет проще.