Включение CORS для шлюза API AWS с помощью AWS CDK

Я пытаюсь создать приложение с помощью AWS CDK, и если бы я собирал приложение вручную, используя консоль AWS, я обычно включал бы CORS в шлюзе API.

Несмотря на то, что я могу экспортировать сваггер из API-шлюза и найти множество вариантов генерации конечной точки Mock для метода OPTIONS, я не вижу, как это сделать с помощью CDK. В настоящее время я пытался:

const apigw             = require('@aws-cdk/aws-apigateway');

где:

var api                 = new apigw.RestApi(this, 'testApi');

и определение метода OPTIONS, например:

const testResource   = api.root.addResource('testresource');

var mock = new apigw.MockIntegration({
                    type: "Mock",
                    methodResponses: [
                            {
                                    statusCode: "200",
                                    responseParameters : {
                                            "Access-Control-Allow-Headers" : "string",
                                            "Access-Control-Allow-Methods" : "string",
                                            "Access-Control-Allow-Origin" : "string"
                                    }
                            }
                    ],
                    integrationResponses: [
                            {
                                    statusCode: "200",
                                    responseParameters: {
                                            "Access-Control-Allow-Headers" :  "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
                                            "Access-Control-Allow-Origin" : "'*'",
                                            "Access-Control-Allow-Methods" : "'GET,POST,OPTIONS'"
                                    }
                            }
                    ],
                    requestTemplates: {
                            "application/json": "{\"statusCode\": 200}"
                    }
            });

            testResource.addMethod('OPTIONS', mock);

Но это не развертывание. Сообщение об ошибке, которое я получаю от развертывания стека облачной информации при запуске "cdk deploy":

Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: Access-Control-Allow-Origin] (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException;

Идеи?

1 ответ

Решение

Я не проверял это сам, но на основе этого ответа кажется, что вам нужно будет использовать немного другой набор ключей при определении вашей интеграции MOCK:

const api = new apigw.RestApi(this, 'api');

const method = api.root.addMethod('OPTIONS', new apigw.MockIntegration({
  integrationResponses: [
    {
      statusCode: "200",
      responseParameters: {
        "method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
        "method.response.header.Access-Control-Allow-Methods": "'GET,POST,OPTIONS'",
        "method.response.header.Access-Control-Allow-Origin": "'*'"
      },
      responseTemplates: {
        "application/json": ""
      }
    }
  ],
  passthroughBehavior: apigw.PassthroughBehavior.Never,
  requestTemplates: {
    "application/json": "{\"statusCode\": 200}"
  },
}));

// since "methodResponses" is not supported by apigw.Method (https://github.com/awslabs/aws-cdk/issues/905)
// we will need to use an escape hatch to override the property

const methodResource = method.findChild('Resource') as apigw.cloudformation.MethodResource;
methodResource.propertyOverrides.methodResponses = [
  {
    statusCode: '200',
    responseModels: {
      'application/json': 'Empty'
    },
    responseParameters: {
      'method.response.header.Access-Control-Allow-Headers': true,
      'method.response.header.Access-Control-Allow-Methods': true,
      'method.response.header.Access-Control-Allow-Origin': true
    }
  }
]

Было бы полезно иметь возможность включать CORS, используя более дружественный API.

Недавнее изменение сделало позволяет CORS проще:

const restApi = new apigw.RestApi(this, `api`, {
  defaultCorsPreflightOptions: {
    allowOrigins: apigw.Cors.ALL_ORIGINS
  }
});

С недавними обновлениями CDK больше нет необходимости использовать аварийный люк.

Эта версия, изначально созданная Heitor Vital на github, использует только собственные конструкции.

export function addCorsOptions(apiResource: apigateway.IResource) {
    apiResource.addMethod('OPTIONS', new apigateway.MockIntegration({
        integrationResponses: [{
        statusCode: '200',
        responseParameters: {
            'method.response.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'",
            'method.response.header.Access-Control-Allow-Origin': "'*'",
            'method.response.header.Access-Control-Allow-Credentials': "'false'",
            'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE'",
        },
        }],
        passthroughBehavior: apigateway.PassthroughBehavior.NEVER,
        requestTemplates: {
        "application/json": "{\"statusCode\": 200}"
        },
    }), {
        methodResponses: [{
        statusCode: '200',
        responseParameters: {
            'method.response.header.Access-Control-Allow-Headers': true,
            'method.response.header.Access-Control-Allow-Methods': true,
            'method.response.header.Access-Control-Allow-Credentials': true,
            'method.response.header.Access-Control-Allow-Origin': true,
        },  
        }]
    })
}

Я также перенес тот же код на Python, используя его версию в качестве ориентира.

def add_cors_options(api_resource):
    """Add response to OPTIONS to enable CORS on an API resource."""
    mock = apigateway.MockIntegration(
        integration_responses=[{
            'statusCode': '200',
            'responseParameters': {
                'method.response.header.Access-Control-Allow-Headers':
                    "'Content-Type,\
                      X-Amz-Date,\
                      Authorization,\
                      X-Api-Key,\
                      X-Amz-Security-Token,X-Amz-User-Agent'",
                'method.response.header.Access-Control-Allow-Origin': "'*'",
                'method.response.header.Access-Control-Allow-Credentials':
                    "'false'",
                'method.response.header.Access-Control-Allow-Methods':
                    "'OPTIONS,\
                      GET,\
                      PUT,\
                      POST,\
                      DELETE'",
            }
        }],
        passthrough_behavior=apigateway.PassthroughBehavior.NEVER,
        request_templates={
            "application/json": "{\"statusCode\": 200}"
        }
    )
    method_response = apigateway.MethodResponse(
        status_code='200',
        response_parameters={
            'method.response.header.Access-Control-Allow-Headers': True,
            'method.response.header.Access-Control-Allow-Methods': True,
            'method.response.header.Access-Control-Allow-Credentials': True,
            'method.response.header.Access-Control-Allow-Origin': True
        }
    )
    api_resource.add_method(
        'OPTIONS',
        integration=mock,
        method_responses=[method_response]
    )

ЗАДНИЙ ПЛАН

Я наткнулся на этот ответ, пытаясь реализовать aws_api_gateway_integration_response в Terraform и случайно наткнулся на решение.

ПРОБЛЕМА

Я получал это сообщение об ошибке:

Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: POST,GET,OPTIONS]

в aws_api_gateway_integration_response ресурс у меня был response_parameter ключ как:

response_parameters = {
    "method.response.header.Access-Control-Allow-Headers" = "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
    "method.response.header.Access-Control-Allow-Origin" = "*"
    "method.response.header.Access-Control-Allow-Methods" = "POST,GET,OPTIONS"
    # "method.response.header.Access-Control-Allow-Credentials" = "false"
  }

Я думал, что все в порядке, так как предполагал, что Terraform нужны двойные кавычки. Однако это было не так.

РЕШЕНИЕ

Мне пришлось добавить одинарные кавычки вокруг значений внутри двойной кавычки. Как это:

response_parameters = {
    "method.response.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
    "method.response.header.Access-Control-Allow-Origin" = "'*'"
    "method.response.header.Access-Control-Allow-Methods" = "'POST,GET,OPTIONS'"
    # "method.response.header.Access-Control-Allow-Credentials" = "false"
  }
Другие вопросы по тегам