阅读背景:

AWS API-Gateway与SNS通信

来源:互联网 

I am building an API which will be serviced by Lambda functions but I need these to be asynchronous so rather than connecting the API-Gateway directly to the Lambda function I'm using the "AWS Service Proxy" to publish SNS messages and then have the Lambda function subscribe to the relevant SNS topic so it receives delivery of the requests. Here's a picture which illustrates the flow:

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

I have tested both the Lambda function in isolation as well pub/sub messaging between SNS and Lambda but I am struggling with the API-Gateway to SNS handoff. Documentation is quite light but what I am assuming right now is that the following attributes must be sent in the POST request:

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

  1. Action: the API-Gateway offers to set this in the UI and I have put in the Publish action which is the appropriate SNS action

    操作:API-Gateway提供在UI中设置它,我已经放入了发布操作,这是适当的SNS操作

  2. Message: the body of the POST message should be a JSON document. It would be passed by the web client and proxied through the gateway to SNS.

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

  3. TopicArn: indicates the SNS topic that we're publishing to. In my design this would be a static value/endpoint so I'd prefer that the web-client not have to pass this too but if it were easier to do this that would be fine too.

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

I have tried lots of things but am just stuck. Would love to find a good code example somewhere but any help at all would be appreciated.

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


Wanted to add a little more context on my current attempt:

想要为我目前的尝试增加更多的背景:

I have tried publishing my API and using Postman to try and get a valid response. Here's the postman screens(one for header vars, one for JSON body):

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

This results in the following error message:

这会导致以下错误消息:

{
   "Error": {
     "Code": "InvalidParameter",
     "Message": "Invalid parameter: TopicArn or TargetArn Reason: no value for required parameter",
     "Type": "Sender"
  },
  "RequestId": "b33b7700-e8a3-58f7-8ebe-39e4e62b02d0"
}

the error seems to indicate that the TopicArn parameter is not being sent to SNS but I have included the following in API-Gateway:

错误似乎表明TopicArn参数没有发送到SNS,但我在API-Gateway中包含以下内容:

5 个解决方案

#1


7  

I'm from the Api Gateway team.

我来自Api Gateway团队。

I believe there are a few formats for the HTTP request to the Publish API, but here's the one I used first:

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

AWS Region us-west-2

AWS Region us-west-2

AWS Service sns

AWS Service sns

AWS Subdomain

AWS子域

HTTP method POST

HTTP方法POST

Action Publish

行动发布

== query strings ==

==查询字符串==

Subject 'foo'
Message 'bar'
TopicArn 'arn:aws:sns:us-west-2:xxxxxxxxxxxx:test-api'

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

This worked for me to publish a message.

这有助于我发布消息。

Let me know if you have further troubles.

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

Jack

插口

#2


5  

I did eventually get this to work after working with AWS support. Here's my solution:

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

  • First of all even though you're sending a POST you will not be able to send a JSON message in the body of the message as you might expect
  • 首先,即使您正在发送POST,您也无法像预期的那样在邮件正文中发送JSON消息
  • Instead you must URL Encode the JSON and pass it as query parameter
  • 相反,您必须URL编码JSON并将其作为查询参数传递
  • Also remember that the JSON you send should start with a root object of default which in SNS-world means the "default channel"
  • 还要记住,您发送的JSON应该以默认的根对象开头,在SNS-world中表示“默认通道”
  • Then, eventually Lambda picks up the SNS event you must also abstract away a lot of the noise to get at your JSON message. For this I created the following function that I use within my Lambda function:
  • 然后,最终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);

#3


1  

You could use API Gateway to invoke your Lambda function asynchronously by configuring it as an AWS service proxy. The configuration is basically the same you see in this GitHub sample, with the exception that the uri for the Lambda invocation changes to /invoke-async/ instead of just /invoke/

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

#4


1  

I am just speculating (haven't tried this myself), but I think you are not sending the message correctly...

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

Based on AWS's documentation here (https://docs.aws.amazon.com/sns/latest/api/API_Publish.html), you need to POST the message in what seems to be the application/x-www-form-urlencoded encoding like this:

根据此处的AWS文档(https://docs.aws.amazon.com/sns/latest/api/API_Publish.html),您需要在似乎是application / x-www-form-urlencoded的情况下发布消息像这样的编码:

POST https://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

That is, the message body looks the way a browser would encode form data. Your message can be JSON formatted, but still needs to be encoded as if it was a form field (an awkward analogy :)).

也就是说,消息体看起来像浏览器对表单数据进行编码的方式。您的消息可以是JSON格式,但仍然需要编码,就像它是一个表单字段(一个尴尬的类比:))。

Also, based on the common parameters documentation (https://docs.aws.amazon.com/sns/latest/api/CommonParameters.html), you have a number of additional required fields (the usual access key, signature and so on).

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

You have not specified what language you are writing your API Gateway in - there might be an AWS SDK for it that you can use, instead of trying to manually compose the REST requests).

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

#5


1  

I would do it like:

我会这样做:

WebApp --> Gateway --> Lambda ( Use Boto3 to publish in SNS ) --> SNS -->Lambda

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

I think, things will be simpler.

我想,事情会变得更简单。


分享到: