使用 AWS CDK 为 AWS API 网关启用 CORS

enabling CORS for AWS API gateway with the AWS CDK

我正在尝试使用 AWS CDK 构建应用程序,如果我要使用 AWS 控制台手动构建应用程序,我通常会在 API 网关中启用 CORS。

尽管我可以从 API 网关中导出 swagger,并且找到了很多选项来为 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" 时,我从 cloudformation 堆栈部署中得到的错误消息是:

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

想法?

我自己还没有测试过,但是基于 this answer,您在定义 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
    }
  }
]

如果能够使用更多 friendly API 来启用 CORS 将会很有用。

编辑:随着 CDK 的更新,不再需要使用逃生舱口。请查看其他答案,因为它们更清晰。

原回答:

This version, originally created by Heitor Vital on github uses only native constructs.

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]
    )

背景

我在尝试在 Terraform 中实现 aws_api_gateway_integration_response 时遇到了这个答案,并且意外地遇到了解决方案。

问题

我收到此错误消息:

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"
  }

recent change 使启用 CORS 变得更简单:

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