AWS API-шлюз, сообщающий SNS

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

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

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

  • Действие: API-шлюз предлагает установить это в пользовательском интерфейсе, и я включил действие Опубликовать, которое является соответствующим действием SNS

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

  • ТемаArn: указывает тему SNS, которую мы публикуем. В моем дизайне это было бы статическим значением/конечной точкой, поэтому я предпочел бы, чтобы веб-клиент не должен был это пропускать, но если бы было легче сделать это, это тоже было бы хорошо.

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


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

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

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

В результате появляется следующее сообщение об ошибке:

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

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

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

Ответ 1

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

  • Прежде всего, даже если вы отправляете POST, вы не сможете отправить сообщение JSON в теле сообщения, как вы могли ожидать
  • Вместо этого вы должны URL-адрес Кодировать JSON и передавать его как параметр запроса
  • Также помните, что отправленный JSON должен начинаться с корневого объекта default, который в SNS-мире означает "канал по умолчанию"
  • Затем, в конце концов, Lambda выбирает событие 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);

Ответ 2

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

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

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

AWS Service sns

Субдомен AWS

HTTP-метод POST

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

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

Тема 'foo'
Message 'bar'
ТемаArn 'arn: aws: sns: us-west-2: xxxxxxxxxxxx: test-api'

Это помогло мне опубликовать сообщение.

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

Джек

Ответ 3

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

Ответ 4

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

Основываясь на документации AWS здесь (http://docs.aws.amazon.com/sns/latest/api/API_Publish.html), вам нужно отправить сообщение POST в то, что похоже на кодировку 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, но оно все равно должно быть закодировано, как если бы это было поле формы (неудобная аналогия:)).

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

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

Ответ 5

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

WebApp → Gateway → Lambda (используйте Boto3 для публикации в SNS) → SNS → Lambda

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

Ответ 6

Если кто-то все еще ищет решение исходной проблемы, возможно, это будет связано с передачей тела запроса JSON в тему SNS только через шлюз API.

Создайте шлюз, как Кен описывает выше. Затем просто передайте тело в параметры запроса Integration Request. Вы также можете жестко закодировать Subject, TopicArn и т.д. Здесь или отобразить их из тела запроса, используя JsonPath.

Например:

{
   //body
   "topic": "arn:aws:sns:1234567:topic"
}

Может быть сопоставлен с заголовком как:

method.request.body.topic

Ответ 7

Я пытался, как вы упомянули, но это не сработало, не могли бы вы предоставить подробный ответ о том, как подключить API-шлюз к SNS для запроса POST на основе JSON. это было бы полезно, так как я попробовал все, и все же я не в состоянии взломать это.