使用 BOTO3 为 AWS Api 网关自动化 CORS

Automating CORS using BOTO3 for AWS Api Gateway

过去几个小时我一直在尝试为 AWS Api 网关配置 CORS。我试图逐字复制 "Enable CORS" 按钮在 aws 控制台中的作用。但是,即使每个方法在控制台中看起来都相同,POSTing 到其余 API 使用 "Enable CORS" 按钮但 returns 使用设置 CORS 时出现 500 权限错误我的代码。

这是与 CORS 设置相关的代码:

# Set the put method response of the POST method
self.apigateway.put_method_response(
    restApiId=self.rest_api['id'],
    resourceId=root_resource['id'],
    httpMethod='POST',
    statusCode='200',
    responseParameters={
        'method.response.header.Access-Control-Allow-Origin': False
    },
    responseModels={
        'application/json': 'Empty'
    }
)

# Set the put integration response of the POST method
self.apigateway.put_integration_response(
    restApiId=self.rest_api['id'],
    resourceId=root_resource['id'],
    httpMethod='POST',
    statusCode='200',
    responseParameters={
        'method.response.header.Access-Control-Allow-Origin': '\'*\''
    },
    responseTemplates={
        'application/json': ''
    }
)

# Add an options method to the rest api
api_method = self.apigateway.put_method(
    restApiId=self.rest_api['id'],
    resourceId=root_resource['id'],
    httpMethod='OPTIONS',
    authorizationType='NONE'
)

# Set the put integration of the OPTIONS method
self.apigateway.put_integration(
    restApiId=self.rest_api['id'],
    resourceId=root_resource['id'],
    httpMethod='OPTIONS',
    type='MOCK',
    requestTemplates={
        'application/json': ''
    }
)

# Set the put method response of the OPTIONS method
self.apigateway.put_method_response(
    restApiId=self.rest_api['id'],
    resourceId=root_resource['id'],
    httpMethod='OPTIONS',
    statusCode='200',
    responseParameters={
        'method.response.header.Access-Control-Allow-Headers': False,
        'method.response.header.Access-Control-Allow-Origin': False,
        'method.response.header.Access-Control-Allow-Methods': False
    },
    responseModels={
        'application/json': 'Empty'
    }
)

# Set the put integration response of the OPTIONS method
self.apigateway.put_integration_response(
    restApiId=self.rest_api['id'],
    resourceId=root_resource['id'],
    httpMethod='OPTIONS',
    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': '\'POST,OPTIONS\'',
        'method.response.header.Access-Control-Allow-Origin': '\'*\''
    },
    responseTemplates={
        'application/json': ''
    }
)

这是通过 AWS 控制台启用 CORS 时 get-method 对 POST 和 OPTIONS 的响应:

{
    "httpMethod": "POST",
    "apiKeyRequired": false,
    "methodIntegration": {
        "httpMethod": "POST",
        "cacheKeyParameters": [],
        "integrationResponses": {
            "200": {
                "responseParameters": {
                    "method.response.header.Access-Control-Allow-Origin": "'*'"
                },
                "statusCode": "200",
                "responseTemplates": {
                    "application/json": null
                }
            }
        },
        "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:477869670267:function:controller/invocations",
        "requestTemplates": {
            "application/json": null
        },
        "cacheNamespace": "o9h9b8tzo2",
        "type": "AWS"
    },
    "methodResponses": {
        "200": {
            "responseParameters": {
                "method.response.header.Access-Control-Allow-Origin": false
            },
            "statusCode": "200",
            "responseModels": {
                "application/json": "Empty"
            }
        }
    },
    "authorizationType": "NONE"
}
{
    "requestParameters": {},
    "httpMethod": "OPTIONS",
    "methodResponses": {
        "200": {
            "statusCode": "200",
            "responseParameters": {
                "method.response.header.Access-Control-Allow-Headers": false,
                "method.response.header.Access-Control-Allow-Methods": false,
                "method.response.header.Access-Control-Allow-Origin": false
            },
            "responseModels": {
                "application/json": "Empty"
            }
        }
    },
    "apiKeyRequired": false,
    "methodIntegration": {
        "cacheNamespace": "o9h9b8tzo2",
        "type": "MOCK",
        "requestTemplates": {
            "application/json": "{\"statusCode\": 200}"
        },
        "integrationResponses": {
            "200": {
                "responseTemplates": {
                    "application/json": null
                },
                "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": "'POST,OPTIONS'",
                    "method.response.header.Access-Control-Allow-Origin": "'*'"
                }
            }
        },
        "cacheKeyParameters": []
    },
    "authorizationType": "NONE"
}

这是使用我的代码启用 CORS 的 get-method 的响应:

{
    "authorizationType": "NONE",
    "httpMethod": "POST",
    "methodIntegration": {
        "requestTemplates": {
            "application/json": null
        },
        "cacheNamespace": "308o168qal",
        "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:477869670267:function:controller/invocations",
        "httpMethod": "POST",
        "cacheKeyParameters": [],
        "integrationResponses": {
            "200": {
                "responseParameters": {
                    "method.response.header.Access-Control-Allow-Origin": "'*'"
                },
                "statusCode": "200",
                "responseTemplates": {
                    "application/json": null
                }
            }
        },
        "type": "AWS"
    },
    "apiKeyRequired": false,
    "methodResponses": {
        "200": {
            "responseParameters": {
                "method.response.header.Access-Control-Allow-Origin": false
            },
            "responseModels": {
                "application/json": "Empty"
            },
            "statusCode": "200"
        }
    }
}
{
    "authorizationType": "NONE",
    "apiKeyRequired": false,
    "methodIntegration": {
        "integrationResponses": {
            "200": {
                "statusCode": "200",
                "responseTemplates": {
                    "application/json": null
                },
                "responseParameters": {
                    "method.response.header.Access-Control-Allow-Methods": "'POST,OPTIONS'",
                    "method.response.header.Access-Control-Allow-Origin": "'*'",
                    "method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
                }
            }
        },
        "cacheNamespace": "bm4zmvzkdk",
        "type": "MOCK",
        "cacheKeyParameters": [],
        "requestTemplates": {
            "application/json": "{\"statusCode\": 200}"
        }
    },
    "requestParameters": {},
    "methodResponses": {
        "200": {
            "statusCode": "200",
            "responseModels": {
                "application/json": "Empty"
            },
            "responseParameters": {
                "method.response.header.Access-Control-Allow-Methods": false,
                "method.response.header.Access-Control-Allow-Origin": false,
                "method.response.header.Access-Control-Allow-Headers": false
            }
        }
    },
    "httpMethod": "OPTIONS"
}

我看不出任何区别,我做错了什么?

根据 AWS 的 MikeD 的请求,POST 请求是从位于 s3 中的文件中的 javascript 发出的:

function post_request() {
    var xhr = new XMLHttpRequest();
    var params = JSON.stringify({
        request: "registerUser",
        user:{ 
            username: document.getElementById("usernameInput").value, 
            email: document.getElementById("emailInput").value,
            password: document.getElementById("passwordInput").value
        }
    });
    xhr.open("POST", "$(endpoint_url)", true);
    xhr.setRequestHeader("Content-type", "application/json");
    xhr.setRequestHeader("x-api-key", "$(api_key)");
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
            if(xhr.status === 200){
                alert("You are registered!");
            }
            else{
                alert("Could not register. Please try again later.");
            }
        }
    };
    xhr.send(params);
    return false;
}

我的设置脚本将 $(endpoint_url) 和 $(api_key) 替换为适当的值(我已确认这些值是准确的)。

这是发出 POST 请求时来自 chrome 控制台的逐字响应:

register.html?X-Amz-Date=20160628T070211Z&X-Amz-Expires=300&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-…:39 OPTIONS https://dn9sjxz0i9.execute-api.us-east-1.amazonaws.com/prod post_request @ register.html?X-Amz-Date=20160628T070211Z&X-Amz-Expires=300&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-…:39document.getElementById.onsubmit @ register.html?X-Amz-Date=20160628T070211Z&X-Amz-Expires=300&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-…:44
register.html?X-Amz-Date=20160628T070211Z&X-Amz-Expires=300&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-…:1 XMLHttpRequest cannot load https://dn9sjxz0i9.execute-api.us-east-1.amazonaws.com/prod. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://s3.amazonaws.com' is therefore not allowed access. The response had HTTP status code 500.

OPTIONS 方法的 put 集成需要一个映射模板,其中包含一个值为 200 的 statusCode。看起来您的代码正在将映射模板设置为空字符串 ('')。当您通过 API 网关创建集成时,它会添加一个默认映射模板:{"statusCode": 200}

将相同的映射模板添加到您的 put 集成中,如下所示:

# Set the put integration of the OPTIONS method
self.apigateway.put_integration(
    restApiId=self.rest_api['id'],
    resourceId=root_resource['id'],
    httpMethod='OPTIONS',
    type='MOCK',
    requestTemplates={
        'application/json': '{"statusCode": 200}'
    }
)