【问题标题】:AWS API-Gateway communicating to SNSAWS API-Gateway 与 SNS 通信
【发布时间】:2016-03-16 18:31:14
【问题描述】:

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

我已经单独测试了 Lambda 函数以及 SNS 和 Lambda 之间的发布/订阅消息,但我在 API-Gateway 到 SNS 切换方面遇到了困难。文档很简单,但我现在假设必须在 POST 请求中发送以下属性:

  1. Action:API-Gateway 提供在 UI 中设置此功能,我已放入 Publish 操作,这是适当的 SNS 操作

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

  3. TopicArn:表示我们要发布到的 SNS 主题。在我的设计中,这将是一个静态值/端点,所以我希望网络客户端也不必传递它,但如果这样做更容易,那也可以。

我尝试了很多东西,但只是卡住了。很想在某个地方找到一个好的代码示例,但我们将不胜感激。


想在我当前的尝试中添加更多上下文:

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

【问题讨论】:

  • 你曾经解决过这个问题吗?我在完全相同的架构下遇到了类似的问题。在我发布一个单独的问题详细说明我的问题之前,我想我会看看你是否能够让它工作。
  • 哦哦。我已经发布了一个答案,但它没有通过。我明天会努力解决这个问题。
  • 您是否设法使用 POST 请求使其运行?我设法做到这一点的唯一方法是将 TopicArn 和 Message 设置为查询字符串参数(如下面提出的答案),因为即使我设置了 POST 方法,请求正文也总是被忽略。我需要请求正文中的内容,但似乎无法将其复制为查询字符串参数。
  • 是的,目前看来您可以使用请求正文。这将在某个时候得到解决,但没有日期。

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


【解决方案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

【讨论】:

    【解决方案2】:

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

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

    “Mapped from”的大小写很重要,它与从 Method Request 配置发送的参数匹配,但发送到 SNS 的是“Integration Request”的“Name”字段,这就是我错了。

    【讨论】:

      【解决方案3】:

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

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

      例如:

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

      可以映射到标题:

      method.request.body.topic
      

      【讨论】:

      • 来说同样的话。这确实应该是公认的答案。
      • 我认为屏幕截图是错误的。它应该只是stageVariables.topicArn,而不是'$stageVariables.TopicArn'
      • 这是有效的。万分感谢。花了 3 天时间弄清楚到底出了什么问题!
      • 如何对主题和主题进行硬编码?我不希望调用者指定它们。谢谢
      • 好的,解决了。您只需在带有刻度 'your-topic-arn' 的集成请求映射中传递它
      【解决方案4】:

      我会这样做:

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

      我想,事情会更简单。

      【讨论】:

      【解决方案5】:

      在与 AWS 支持人员合作后,我最终确实做到了这一点。这是我的解决方案:

      • 首先,即使您发送的是POST,您也将无法像您所期望的那样在消息正文中发送 JSON 消息
      • 相反,您必须对 JSON 进行 URL 编码并将其作为查询参数传递
      • 还请记住,您发送的 JSON 应该以 default 的根对象开头,这在 SNS 世界中意味着“默认通道”
      • 然后,最终 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 天遇到这个问题并且卡住了。问题是我不清楚你上面给出的解决方案。提前致谢。
      • @WilliamFrancisGomes 不确定还要添加什么...“处理程序”函数为您提供 event 对象,但如果您使用 SNS 触发事件,您将获得完整的 SNS 事件.对我来说,除了e.Records[0].Sns.Message 中的内容之外,SNS 详细信息不是很有用,因此上述函数解开了我关心的部分。
      • 请注意,现在 API Gateway 提供了一种直接调用 Lambda 异步调用它的方式,因此在某些情况下您不需要 使用 SNS .
      • 我的问题在这里详细描述:stackoverflow.com/questions/38229941/…
      • @WilliamFrancisGomes 您正在尝试做的事情绝对是可以实现的,并且是 SNS 的一个很好的用例。事情在链条中的哪些地方发生了故障? API-Gateway 是否会触发 SNS 消息(如果您有任何疑问,可以通过电子邮件订阅 SNS 主题)?如果是,您的 lambda 函数是否执行?我需要更深入地了解链条中哪些地方不适合您。
      【解决方案6】:

      我来自 Api Gateway 团队。

      我相信对 Publish API 的 HTTP 请求有几种格式,但这是我第一次使用的格式:

      AWS 区域 us-west-2

      AWS 服务 sns

      AWS 子域

      HTTP 方法 POST

      动作发布

      == 查询字符串 ==

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

      这对我发布消息很有用。

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

      杰克

      【讨论】:

      • 如何将请求正文和请求中发送的参数映射到 SNS 的主题、消息和 TopicArn?
      【解决方案7】:

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

      根据此处的 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 开发工具包,而不是尝试手动编写 REST 请求)。

      【讨论】:

      • WRT 转语言,这个流程最后的 Lambda 函数是 Node JS,调用 Web 客户端是一个 JS SPA (EmberJS)。在两者之间——消息转换发生的地方——只是 API 网关配置。
      • 您给出的示例消息看起来确实像它的 urlencoded,上面的示例似乎表明您可以将 JSON 传递到正文消息中(至少我是这么读的)。跨度>
      • 另外,我假设访问密钥的签名和传递都由 API-Gateway 处理,因为这会破坏他们似乎正在推广的“仅配置”方法(并且 UI 确实要求执行 arn)
      • 道歉 - 我的回答完全不正确。我虽然 API Gateway 是你写的一个组件(没有意识到 AWS 有这样一个产品:)。
      • 谢谢,我需要我能得到的所有帮助。 :)
      【解决方案8】:

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

      【讨论】:

      • 我对你的例子有点困惑。这个 YAML 去哪里了? API-Gateway 可以导入 Swagger 定义吗?
      • 另请注意,invoke-async 已被弃用......他们建议使用 invoke 代替(我相信有一个参数可以将其设置为异步)
      • 是否可以为我使用 UI 设置的 API 导出 Swagger YAML 定义?很高兴能以 YAML 形式看到它,而不仅仅是 UI。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 2016-05-18
      • 2019-01-07
      • 2019-03-22
      • 2020-07-01
      相关资源
      最近更新 更多