API 网关未向 SQS 发送完整的请求正文

问题描述 投票:0回答:1

我正在尝试将完整的请求正文作为消息发送到 SQS。但是,API Gateway 只发送部分请求正文。有什么办法解决这个问题吗?

我的API网关设置如下:

我与 Postman 一起使用的示例标头:

Content-Type: application/json

stripe-signature: t=1702112345,v1=82872ac5c8be8f30a963c6922ab47ce47f123456be9f992492fe78107f86b2fe,v0=f01bd2a1da1234567a487860b7f5625d225e5cd5aae76c7a786fc886f2e6c04c

我与 Postman 一起使用的示例请求正文:

{
  "id": "evt_1OLJecAYjghwsx12QOJm8jS6",
  "object": "event",
  "api_version": "2023-10-16",
  "created": 1702101886,
  "data": {
    "object": {
      "id": "cs_test_a1GNkCx4LlmaoVdoDVWKDffNjXUpOPOPO1n05SDyGHYcHqpbpsqowAhkuR",
      "object": "checkout.session",
      "after_expiration": null,
      "allow_promotion_codes": null,
      "amount_subtotal": 111,
      "amount_total": 111,
      "automatic_tax": {
        "enabled": false,
        "status": null
      },
      "billing_address_collection": null,
      "cancel_url": "http://localhost:3000/search-params?search=hour&success=false",
      "client_reference_id": null,
      "client_secret": null,
      "consent": null,
      "consent_collection": null,
      "created": 1702101865,
      "currency": "cad",
      "currency_conversion": null,
      "custom_fields": [
      ],
      "custom_text": {
        "after_submit": null,
        "shipping_address": null,
        "submit": null,
        "terms_of_service_acceptance": null
      },
      "customer": "cus_I9i1CAD0zq2XaR",
      "customer_creation": null,
      "customer_details": {
        "address": {
          "city": null,
          "country": "CA",
          "line1": null,
          "line2": null,
          "postal_code": "V3F 5Y3",
          "state": null
        },
        "email": "[email protected]",
        "name": "adfsaf",
        "phone": null,
        "tax_exempt": "none",
        "tax_ids": [
        ]
      },
      "customer_email": null,
      "expires_at": 1702188265,
      "invoice": null,
      "invoice_creation": {
        "enabled": false,
        "invoice_data": {
          "account_tax_ids": null,
          "custom_fields": null,
          "description": null,
          "footer": null,
          "metadata": {
          },
          "rendering_options": null
        }
      },
      "livemode": false,
      "locale": null,
      "metadata": {
      },
      "mode": "payment",
      "payment_intent": "pi_3OLJeaAYasdfgh452me8h1Px",
      "payment_link": null,
      "payment_method_collection": "if_required",
      "payment_method_configuration_details": null,
      "payment_method_options": {
      },
      "payment_method_types": [
        "card"
      ],
      "payment_status": "paid",
      "phone_number_collection": {
        "enabled": false
      },
      "recovered_from": null,
      "setup_intent": null,
      "shipping_address_collection": null,
      "shipping_cost": null,
      "shipping_details": null,
      "shipping_options": [
      ],
      "status": "complete",
      "submit_type": null,
      "subscription": null,
      "success_url": "http://localhost:3000/search-params?search=hour&success=true",
      "total_details": {
        "amount_discount": 0,
        "amount_shipping": 0,
        "amount_tax": 0
      },
      "ui_mode": "hosted",
      "url": null
    }
  },
  "livemode": false,
  "pending_webhooks": 1,
  "request": {
    "id": null,
    "idempotency_key": null
  },
  "type": "checkout.session.completed"
}

API 网关发送到 SQS 的示例请求正文。请注意它只是请求正文的一部分:

2023-12-09T06:12:36.193Z    8a8bb59f-02ef-5eb3-8df2-e871056a9c62    INFO    Processed message {"id":"evt_1OLJecASdfghjkl45QOJm8jS6","object":"event","api_version":"2023-10-16","created":1702101886,"data":{"object":{"id":"cs_test_a1GNkCx4LlprvVdoDVWKDffNjXUpPOIUY1n05SDyGHYcHasdfghjkAhkuR","object":"checkout.session","after_expiration":null,"allow_promotion_codes":null,"amount_subtotal":111,"amount_total":111,"automatic_tax":{"enabled":false,"status":null},"billing_address_collection":null,"cancel_url":"http://localhost:3000/search-params?search=hour

用于生成 API 网关的 Terraform 代码:

# Create an HTTP API Gateway
resource "aws_api_gateway_rest_api" "stripe_webhook_api" {
  name = "stripe-webhook-http-api"
  description = "stripe webhook"
}

#Configure API Gateway resource
resource "aws_api_gateway_resource" "stripe_webhook_api_resource" {
  rest_api_id = aws_api_gateway_rest_api.stripe_webhook_api.id
  parent_id   = aws_api_gateway_rest_api.stripe_webhook_api.root_resource_id
  path_part   = var.path
}

#Configure API Gateway method request
resource "aws_api_gateway_method" "stripe_webhook_api_method" {
  rest_api_id   = aws_api_gateway_rest_api.stripe_webhook_api.id
  resource_id   = aws_api_gateway_resource.stripe_webhook_api_resource.id
  http_method   = "POST"
  authorization = "NONE"
  request_parameters = {
    "method.request.header.stripe-signature" = true,
  }
}

#Configure API Gateway integration
resource "aws_api_gateway_integration" "stripe_webhook_api_integration" {
  rest_api_id             = aws_api_gateway_rest_api.stripe_webhook_api.id
  resource_id             = aws_api_gateway_resource.stripe_webhook_api_resource.id
  http_method             = aws_api_gateway_method.stripe_webhook_api_method.http_method
  integration_http_method = "POST"
  type                    = "AWS"
  uri                     = join("", ["arn:aws:apigateway:", var.region, ":sqs:path/", data.aws_caller_identity.current.account_id, "/", aws_sqs_queue.stripe_webhook_sqs.name])
  credentials             = aws_iam_role.stripe_webhook_APIGW_to_SQS_Role.arn
  request_parameters = {
    "integration.request.header.Content-Type"                              = "'application/x-www-form-urlencoded'"
    "integration.request.querystring.MessageAttribute.1.Name"              = "'stripeSignature'"
    "integration.request.querystring.MessageAttribute.1.Value.DataType"    = "'String'"
    "integration.request.querystring.MessageAttribute.1.Value.StringValue" = "method.request.header.stripe-signature"
  }
  request_templates = {
    "application/json" = "Action=SendMessage&MessageBody=$input.json('$')"
  }
  passthrough_behavior = "NEVER"
}

# Configure API Gateway to push all logs to CloudWatch Logs
resource "aws_api_gateway_method_settings" "StripeWebhookGatewaySettings" {
  rest_api_id = aws_api_gateway_rest_api.stripe_webhook_api.id
  stage_name  = aws_api_gateway_stage.StripeWebhookGatewayStage.stage_name
  method_path = "*/*"

  settings {
    # Enable CloudWatch logging and metrics
    metrics_enabled = true
    logging_level   = "INFO"
  }
}

# Configure API Gateway integration response
resource "aws_api_gateway_integration_response" "stripe_webhook_api_integration_response" {
  rest_api_id = aws_api_gateway_rest_api.stripe_webhook_api.id
  resource_id = aws_api_gateway_resource.stripe_webhook_api_resource.id
  http_method = aws_api_gateway_method.stripe_webhook_api_method.http_method
  status_code = aws_api_gateway_method_response.stripe_webhook_api_method_response.status_code
}

# Configure API Gateway method response
resource "aws_api_gateway_method_response" "stripe_webhook_api_method_response" {
  rest_api_id = aws_api_gateway_rest_api.stripe_webhook_api.id
  resource_id = aws_api_gateway_resource.stripe_webhook_api_resource.id
  http_method = aws_api_gateway_method.stripe_webhook_api_method.http_method
  status_code = "200"
  response_models = {
    "application/json" = "Empty"
  }
}

# Create a new API Gateway deployment for the created rest api
resource "aws_api_gateway_deployment" "stripe_webhook_api_deployment" {
  depends_on  = [aws_api_gateway_integration.stripe_webhook_api_integration]
  rest_api_id = aws_api_gateway_rest_api.stripe_webhook_api.id
  lifecycle {
    create_before_destroy = true
  }
}

# Create a Log Group for API Gateway to push logs to
resource "aws_cloudwatch_log_group" "stripe_webhook_APIGW_logGroup" {
  name_prefix = "/aws/stripe-webhook-APIGW/terraform"
}

# Create a Log Policy to allow Cloudwatch to Create log streams and put logs
resource "aws_cloudwatch_log_resource_policy" "stripe_webhook_APIGW_logPolicy" {
  policy_name     = "Terraform-stripe_webhook_APIGW_logPolicy-${data.aws_caller_identity.current.account_id}"
  policy_document = data.template_file.stripe_webhook_APIGW_logPolicy_template.rendered
}


# Create a new API Gateway stage with logging enabled
resource "aws_api_gateway_stage" "StripeWebhookGatewayStage" {
  deployment_id = aws_api_gateway_deployment.stripe_webhook_api_deployment.id
  rest_api_id   = aws_api_gateway_rest_api.stripe_webhook_api.id
  stage_name    = "default"

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.stripe_webhook_APIGW_logGroup.arn
    format = join(", ", ["{ \"requestId\":\"$context.requestId\"",
      "\"ip\":\"$context.identity.sourceIp\"",
      "\"requestTime\":\"$context.requestTime\"",
      "\"httpMethod\":\"$context.httpMethod\"",
      "\"routeKey\":\"$context.routeKey\"",
      "\"status\":\"$context.status\",\"protocol\":\"$context.protocol\"",
      "\"responseLength\":\"$context.responseLength\"",
      "\"authorizererror\":\"$context.authorizer.error\"",
      "\"errormessage\":\"$context.error.message\"",
      "\"errormessageString\":\"$context.error.messageString\"",
      "\"errorresponseType\":\"$context.error.responseType\"",
      "\"integrationerror\":\"$context.integration.error\"",
    "\"integrationErrorMessage\":\"$context.integrationErrorMessage\" }"])
  }
}

我还确保为 SQS 创建正确的角色和策略以从 API 网关接收消息:

API 网关到 SQS 角色:

{
  "Version" : "2012-10-17",
  "Statement" : [
    {
      "Effect" : "Allow",
      "Principal" : {
        "Service" : "apigateway.amazonaws.com"
      },
      "Action" : "sts:AssumeRole"
    }
  ]
}

SQS 策略的 API 网关:

{
  "Version" : "2012-10-17",
  "Statement" : [
    {
      "Effect" : "Allow",
      "Action" : [
        "sqs:SendMessage",
        "sqs:ListQueues"
      ],
      "Resource" : "${sqsarn}"
    }
  ]
}
amazon-web-services terraform aws-api-gateway
1个回答
0
投票

如果正文有 & 字符,则需要 $util.urlEncode 方法。

这里是更详细地描述问题和解决方案的链接。

https://medium.com/@thehouseofcards/fixing-a-common-gotcha-in-aws-api-gateway-integration-with-sqs-d857f65179b8

我的下一步是弄清楚如何让 Terraform 在 API 发生更改时重新部署 API。我正在研究的一种解决方案是

https://developer.hashicorp.com/terraform/language/resources/terraform-data

这看起来很糟糕,但它比从 AWS 控制台手动重新部署 API 更好。如果有人对此有任何建议,请随时发表评论。

© www.soinside.com 2019 - 2024. All rights reserved.