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. это было бы полезно, так как я попробовал все, и все же я не в состоянии взломать это.