AWS API-Gateway 与 SNS 通信

AWS API-Gateway communicating to SNS

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

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

  1. Action:API-Gateway 提议在 UI 中进行设置,我已将其放入 发布 操作,这是适当的 SNS 操作

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

  3. TopicArn:指示我们要发布到的 SNS 主题。在我的设计中,这将是一个静态的 value/endpoint,所以我更希望 web-client 不必也通过它,但如果这样做更容易,那也很好。

我尝试了很多东西,但还是卡住了。很想在某处找到一个好的代码示例,但任何帮助都将不胜感激。


想为我当前的尝试添加更多背景信息:

我已尝试发布我的 API 并使用 Postman 尝试获得有效回复。这是邮递员屏幕(一个用于 header 变量,一个用于 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-Gateway 中包含以下内容:

您可以使用 API 网关通过将其配置为 AWS 服务代理来异步调用您的 Lambda 函数。配置与您在 this GitHub sample, with the exception that the uri for the Lambda invocation changes to /invoke-async/ 中看到的基本相同,而不仅仅是 /invoke/

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

根据此处的 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 网关的语言 - 您可能可以使用适用于它的 AWS SDK,而不是尝试手动编写 REST 请求)。

我来自 Api Gateway 团队。

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

AWS 区域 us-west-2

AWS 服务 sns

AWS 子域

HTTP 方法 POST

动作发布

== 查询字符串 ==

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

这对我发布消息有用。

如果您还有其他问题,请告诉我。

杰克

在与 AWS 支持部门合作后,我最终确实成功了。这是我的解决方案:

  • 首先,即使您发送的是 POST,您也 无法在邮件正文中发送 JSON 邮件如您所料
  • 相反,您必须 URL 编码 JSON 并将其作为查询参数传递
  • 还要记住,您发送的 JSON 应该以 default 的根对象开头,在 SNS 世界中这意味着 "default channel"
  • 然后,最终 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);

我会这样做:

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

我想,事情会简单一些。

如果 body 仍在寻找原始问题的解决方案,仅通过 API 网关将 JSON 请求 body 代理到 SNS 主题,它是可能的。

按照 Ken 上面的描述创建网关。然后简单地将 body 代理到 Integration Request's query parameters. You can also hard code Subject, TopicArn, etc here, or map those from the request's body using a JsonPath.

例如:

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

可以映射到 header 为:

method.request.body.topic

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

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

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

这里有一个分步指南,供阅读以上答案后仍然无法理解的人使用。变量名称区分大小写,因此请确保准确无误。

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

  2. Return 到 Post 方法并打开 集成请求
    一种。展开 URL 查询字符串参数
    b.添加以下两个查询字符串参数
    名称: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"

Sources/Further 资料:
API Gateway Proxy Integration Service Guide
SNS Publish Method Documentation