无法从 API 网关向 SNS 主题发送大负载

Unable to send large payload to SNS topic from API Gateway

我已经实现了一个 API 网关端点,它在新请求到来时向 SNS 主题发送消息。通常,除了我尝试向 SNS 主题发送大量有效负载的情况外,它工作得很好。在这种情况下,即使我没有超过 SNS 或 API 网关限制和配额,我也会收到来自 SNS API 的错误请求。 例如,如果我将发送下一个包含 15k 个字母 'a' 的有效负载,或者如果数组将包含大约 8k 个整数,我将收到此消息:

{ "count": 1, "data": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa... .", "flag": 1, "arr": 1 }

据我所知,这种行为的原因隐藏在我的 CloudFormation 模板的下一行代码中:

integration.request.querystring.Message: "method.request.body"
integration.request.querystring.TopicArn: !Sub "'${some-topic-arn}'"

根据 documentation 我们可以使用 body 类型而不是 querystring 但它不起作用。 此外,我尝试使用请求模板映射并通过查询字符串发送 topicArn 并通过模板映射发送消息。但它也不起作用。

那么谁能告诉我我做错了什么以及如何解决通过 HTTP POST 请求发送大负载时收到错误请求错误的问题?

这是我当前的 CloudFormation 模板: /v1/someApiEndpoint: post: 请求正文: 内容: application/json: 模式: $ref: "#/components/schemas/SomeApiModel" 要求:真实 回应: '200': 描述:“200响应” ....

            '500':
              description: "500 response"
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/ErrorMessage"

          x-amazon-apigateway-request-validator: "SomeApiModelValidator"
          x-amazon-apigateway-integration:
            type: "aws"
            httpMethod: "POST"
            uri: !Sub "arn:aws:apigateway:${AWS::Region}:sns:action/Publish"
            credentials: !GetAtt SomeApiRole.Arn
            responses:
              '2\d{2}':
                statusCode: 200
            requestParameters:
              integration.request.header.Content-Type: "'application/x-www-form-urlencoded'"
              integration.request.querystring.Message: "method.request.body"
              integration.request.querystring.TopicArn: !Sub "'${SomeTopicArn}'"
            passthroughBehavior: "NEVER"
            requestTemplates:
              application/json: |
               #set($input.path('$').payload = { "userIdentity": $util.parseJson($context.authorizer.userIdentity), "data": $util.parseJson($input.body) })
               #set($encodedJson = $util.urlEncode($input.json('$.payload')))

这是我发送到 API 网关然后传输到 SNS 主题的模型定义:

class SomeApiModel
{
  int count; 
  string data; 
  int flag;
  int[] arr;
}

好的,我明白了。

经过许多小时的调查,我终于找到了问题并解决了它。 正如 Michael-sqlbot in the next 所提到的,我们需要覆盖 SNS 发布端点的路径。 顺便说一句,谢谢你救了我的命 =)

如果有人也会遇到这个问题,这里有一个解决方案:

  1. 首先。将 URI 属性 替换为 x-amazon-apigateway-integration: 部分:

uri: !Sub "arn:aws:apigateway:${AWS::Region}:sns:action/Publish"`

对此:

uri: !Sub "arn:aws:apigateway:${AWS::Region}:sns:path//"

它将覆盖路径为

  1. 从集成请求参数部分删除接下来的两行代码:
integration.request.querystring.Message: "method.request.body"
integration.request.querystring.TopicArn: !Sub "'${SomeTopicArn}'"
  1. 将 TopicArn、Message 和 Action 参数放入正文请求模板中: 请求模板:
application/json:
    !Sub Action=Publish&TopicArn=$util.urlEncode('${my-topic-arn}')&Message=$util.urlEncode($input.body)##

这是此集成的完整 CloudFormation 模板定义:

             x-amazon-apigateway-integration:
                type: "aws"
                httpMethod: "POST"
                uri: !Sub "arn:aws:apigateway:${AWS::Region}:sns:path//"
                credentials: !GetAtt my-personal-role.Arn
                responses:
                  '2\d{2}':
                    statusCode: 200
                requestParameters:
                  integration.request.header.Content-Type: "'application/x-www-form-urlencoded'"
                passthroughBehavior: "NEVER"
                requestTemplates:
                  application/json:
                    !Sub Action=Publish&TopicArn=$util.urlEncode('${my-topic-arn}')&Message=$util.urlEncode($input.body)##

注意 Content-Type 属性。它应该被单引号括起来作为一个单词。