AWS API-Gateway与SNS通信

时间:2015-12-10 23:11:43

标签: amazon-web-services amazon-sns aws-api-gateway

我正在构建一个由Lambda函数提供服务的API,但我需要这些API是异步的,而不是将API-Gateway直接连接到Lambda函数我使用" AWS服务代理&# 34; 发布 SNS消息,然后让Lambda函数订阅相关的SNS主题,以便它接收请求的传递。这是一张说明流程的图片:

enter image description here

我已经单独测试了Lambda函数以及SNS和Lambda之间的pub / sub消息传递,但我正在努力使用API​​-Gateway进行SNS切换。文档非常简单但我现在假设的是必须在POST请求中发送以下属性:

  1. 操作:API-Gateway提供在UI中设置此功能,我已添加发布操作,这是相应的SNS操作

  2. 消息:POST消息的正文应该是JSON文档。它将由Web客户端传递,并通过网关代理到SNS。

  3. TopicArn :表示我们要发布的SNS主题。在我的设计中,这将是一个静态值/端点,所以我更喜欢网络客户端也不必通过它,但如果更容易做到这一点也会没问题。

  4. 我尝试过很多东西,但我只是卡住了。很想在某处找到一个好的代码示例,但任何帮助都会受到赞赏。

    希望在我目前的尝试中添加更多背景信息:

    我尝试发布我的API并使用Postman尝试获得有效的响应。这是邮递员屏幕(一个用于标题变量,一个用于JSON正文):

    header variables 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"
    }
    

    该错误似乎表明 TopicArn 参数未发送到SNS,但我在API网关中包含以下内容:

    enter image description here

8 个答案:

答案 0 :(得分:8)

我来自Api Gateway团队。

我相信发布API的HTTP请求有几种格式,但这是我首先使用的格式:

AWS Region us-west-2

AWS Service sns

AWS子域

HTTP方法POST

行动发布

==查询字符串==

主题'foo'
消息'bar'
TopicArn'arn:aws:sns:us-west-2:xxxxxxxxxxxx:test-api'

这对我发布了一条消息。

如果您有进一步的麻烦,请告诉我。

杰克

答案 1 :(得分:6)

在使用AWS支持后,我最终确保了这一点。这是我的解决方案:

  • 首先,即使你发送了POST,你也 能够像你期望的那样在邮件正文中发送JSON邮件
  • 相反,您必须对JSON进行编码并将其作为查询参数传递
  • 还要记住,您发送的JSON应以default的根对象开头,在SNS-world中表示“默认频道”
  • 然后,最终Lambda获得了SNS事件,您还必须抽出大量噪音来获取您的JSON消息。为此我创建了我在Lambda函数中使用的以下函数:

/**
 * 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 :(得分:1)

您可以使用API​​网关通过将其配置为AWS服务代理来异步调用Lambda函数。配置与this GitHub sample中的配置基本相同,但Lambda调用的uri更改为/invoke-async/而不是/ invoke /

答案 3 :(得分:1)

我只是猜测(我自己没试过),但我认为你没有正确发送信息......

根据此处的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格式的,但仍然需要编码,就好像它是一个表单字段(一个尴尬的类比:))。

此外,根据常用参数文档(http://docs.aws.amazon.com/sns/latest/api/CommonParameters.html),您还有许多其他必填字段(通常的访问密钥,签名等)。

您尚未指定编写API网关的语言 - 您可以使用AWS SDK,而不是尝试手动编写REST请求。)

答案 4 :(得分:1)

我会这样做:

WebApp - >网关 - > Lambda(使用Boto3在SNS中发布) - > SNS - > Lambda

我认为事情会更简单。

答案 5 :(得分:1)

还请记住,参数区分大小写;我还收到了OP的错误:"Message": "Invalid parameter: TopicArn or TargetArn Reason: no value for required parameter"

唯一的问题是参数是否区分大小写(具体来说应该是:“ TopicArn”和“ Message”)。这些是在“方法执行” |“方法执行”中设置的。 POST-集成请求部分,在“名称”字段中。

“映射自”的大小写很重要,因为它与从“方法请求”配置中发送来的参数匹配,但是发送到SNS的是“集成请求”的“名称”字段,这就是我错了。

enter image description here

答案 6 :(得分:1)

这里有一个分步指南,供在浏览上述答案后仍然无法弄清楚的人使用。变量名称区分大小写,因此请确保准确无误。

  1. 打开发布方法
    一种。选择方法请求
    湾将请求验证器更改为 Validate body, query string parameters, and headers
    C。展开 URL 查询字符串参数
    d.添加以下两个查询字符串参数
    名称:TopicArn ----> 选择必填
    名称:Message -----> 选择必填

  2. 返回 Post 方法并打开集成请求
    一种。展开 URL 查询字符串参数
    湾添加以下两个查询字符串参数
    名称:TopicArn 映射自:method.request.querystring.TopicArn
    名称:Message 映射自:method.request.querystring.Message

  3. 测试时,更改以下命令以匹配您的 SNS ARN 并将其放入查询字符串中。
    TopicArn=arn:aws:sns:us-west-2:1234567890:SNSName&Message="Hello from API Gateway"

来源/更多信息:
API Gateway Proxy Integration Service Guide
SNS Publish Method Documentation

答案 7 :(得分:0)

如果有人仍在寻找解决原始问题的方法,仅通过API网关将JSON请求主体代理到SNS主题,就可以实现。

按照Ken上面的描述创建网关。然后只需将正文代理到Integration Request's query parameters。您还可以在此处硬编码Subject,TopicArn等,或使用JsonPath从请求的正文中映射它们。

例如:

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

可以按以下方式映射到标头:

method.request.body.topic