AWS API-шлюз для связи с SNS
Я создаю API, который будет обслуживаться лямбда-функциями, но мне нужно, чтобы они были асинхронными, поэтому вместо подключения API-шлюза непосредственно к функции лямбда я использую "AWS Service Proxy" для публикации сообщений SNS, а затем заставляю функцию Lambda подписаться на соответствующую тему SNS, чтобы она получала доставку запросов. Вот картина, которая иллюстрирует этот поток:
Я проверил обе лямбда-функции изолированно. а также pub/sub обмен сообщениями между SNS и Lambda, но я борюсь с API-шлюзом для передачи SNS. Документация довольно легкая, но сейчас я предполагаю, что в запросе POST должны быть отправлены следующие атрибуты:
-
Действие : API-шлюз предлагает установить это в UI, и я ввел действие Publish , которое является соответствующим действием SNS
-
Message : тело сообщения POST должно быть JSON документ. Он будет передан веб-клиентом и проксирован через шлюз в SNS.
-
TopicArn : указывает тему SNS, которую мы публикуем. В моем дизайне это будет статическое значение / конечная точка, поэтому я предпочел бы, чтобы веб-клиент не должен был передавать это тоже, но если бы это было проще сделать, это тоже было бы прекрасно.
Я перепробовал много вещей, но просто застрял. Хотел бы найти хороший пример кода где-нибудь, но любая помощь вообще будет оцененный.
Хотел добавить немного больше контекста к моей текущей попытке:
Я попытался опубликовать свой API и использовать Postman, чтобы попытаться получить правильный ответ. Вот экраны почтальона(один для заголовка vars, один для тела 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 ответов:
Я из команды 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).