我正在使用 terraform 与 AWS 提供商来创建 API 网关。除了 CORS 设置之外,一切似乎都很好。我还使用 OpenAPI 进行配置。
我的“最终用户”问题是,我对后端的 API 调用返回 404 not found,因为它首先发出 OPTIONS 请求。在 API Gateway 中启用 CORS 设置可以为您处理 CORS,并自动返回 OPTIONS 请求的正确响应。但是,CORS 设置尚未启用。我相信它们应该是由于 x-amazon-apigateway-cors 部分造成的。
这是我的 OpenAPI 文件:
openapi: 3.0.1
info:
title: App API
description: App API
version: 0.1.0
paths:
'/requisitions':
post:
operationId: createRequisition
summary: Create requisition
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- institutionId
properties:
institutionId:
type: string
responses:
'200':
description: 200 response
content:
application/json:
schema:
$ref: '#/components/schemas/Requisition'
'401':
$ref: '#/components/responses/Unauthenticated'
default:
$ref: '#/components/responses/Error'
x-amazon-apigateway-integration:
type: AWS_PROXY
httpMethod: POST
uri: '${gocardless_function_arn}'
payloadFormatVersion: 2.0
security:
- cognito-jwt: []
x-amazon-apigateway-cors:
allowOrigins:
- '*'
allowMethods:
- GET
- OPTIONS
- POST
allowHeaders:
- x-amzm-header
- x-apigateway-header
- x-api-key
- authorization
- x-amz-date
- content-type
components:
schemas:
AnyValue:
nullable: true
description: Can be any value - null, string, number, boolean, array or object.
Requisition:
type: object
properties:
id:
type: string
nullable: true
Error:
type: object
required:
- status
- statusCode
- error
properties:
status:
type: string
statusCode:
type: integer
requestId:
type: string
documentationUrl:
type: string
error:
type: object
required:
- code
- message
- timestamp
properties:
code:
type: string
message:
type: string
details:
$ref: '#/components/schemas/AnyValue'
timestamp:
type: string
path:
type: string
suggestion:
type: string
securitySchemes:
cognito-jwt:
type: oauth2
flows:
authorizationCode:
authorizationUrl: 'https://cognito-idp.eu-west-2.amazonaws.com/'
tokenUrl: ''
scopes: {}
x-amazon-apigateway-authorizer:
type: jwt
jwtConfiguration:
issuer: 'https://cognito-idp.eu-west-2.amazonaws.com/${cognito_user_pool_id}'
audience:
- '${cognito_app_client_id}'
identitySource: '$request.header.Authorization'
responses:
Unauthenticated:
description: Unauthenticated
headers:
www-authenticate:
schema:
type: string
content:
application/json:
schema:
type: object
required:
- message
properties:
message:
type: string
Error:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
这是我的地形的相关部分:
resource "aws_apigatewayv2_api" "api_gateway" {
name = "API Gateway"
version = "0.1.0"
protocol_type = "HTTP"
description = "API gateway"
body = templatefile("${path.module}/files/api-gateway-openapi.yaml", {
gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn,
cognito_user_pool_id = aws_cognito_user_pool.pool.id,
cognito_app_client_id = aws_cognito_user_pool_client.client.id,
region = var.region
})
}
resource "aws_apigatewayv2_deployment" "api_gateway_deployment" {
api_id = aws_apigatewayv2_api.api_gateway.id
description = "API Gateway deployment"
triggers = {
redeployment = sha1(join(
",", tolist([
templatefile("${path.module}/files/api-gateway-openapi.yaml", {
gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn,
cognito_user_pool_id = aws_cognito_user_pool.pool.id,
cognito_app_client_id = aws_cognito_user_pool_client.client.id,
region = var.region
}),
jsonencode(aws_apigatewayv2_stage.api_gateway_default_stage)
])
))
}
}
resource "aws_apigatewayv2_stage" "api_gateway_default_stage" {
api_id = aws_apigatewayv2_api.api_gateway.id
name = "default"
auto_deploy = true
default_route_settings {
throttling_rate_limit = 10
throttling_burst_limit = 10
}
}
我尝试通过 AWS 控制台中的“ClickOps”手动启用 CORS。来自我前端的请求立即开始工作(选项,然后是 POST)。
我期待 x-amazon-apigateway-cors (https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-cors-configuration.html) 部分已经启用了这些 CORS 选项,而无需我手动执行它们。通过手动执行它们,每次我重新运行时它们也会被覆盖
terraform apply
。
我应该在 OpenAPI 文件中更改哪些内容才能在 API GW 中启用 CORS 配置?
您需要为选项添加模拟集成的想法。我已经编写了一个将 CORS 应用于 API 网关的模块,因此 main.tf 将是。
####CORS####
resource "aws_api_gateway_resource" "cors" {
rest_api_id = var.api_id
parent_id = var.api_resource_id
path_part = "{cors+}"
}
resource "aws_api_gateway_method" "cors" {
rest_api_id = var.api_id
resource_id = aws_api_gateway_resource.cors.id
http_method = "OPTIONS"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "cors" {
rest_api_id = var.api_id
resource_id = aws_api_gateway_resource.cors.id
http_method = aws_api_gateway_method.cors.http_method
type = "MOCK"
request_templates = {
"application/json" = jsonencode(
{
statusCode = 200
}
)
}
}
resource "aws_api_gateway_method_response" "cors" {
depends_on = [aws_api_gateway_method.cors]
rest_api_id = var.api_id
resource_id = aws_api_gateway_resource.cors.id
http_method = aws_api_gateway_method.cors.http_method
status_code = 200
response_parameters = {
"method.response.header.Access-Control-Allow-Origin" = true,
"method.response.header.Access-Control-Allow-Methods" = true,
"method.response.header.Access-Control-Allow-Headers" = true
}
response_models = {
"application/json" = "Empty"
}
}
resource "aws_api_gateway_integration_response" "cors" {
depends_on = [aws_api_gateway_integration.cors, aws_api_gateway_method_response.cors]
rest_api_id = var.api_id
resource_id = aws_api_gateway_resource.cors.id
http_method = aws_api_gateway_method.cors.http_method
status_code = 200
response_parameters = {
"method.response.header.Access-Control-Allow-Origin" = "'*'", # replace with hostname of frontend (CloudFront)
"method.response.header.Access-Control-Allow-Headers" = "'Content-Type'",
"method.response.header.Access-Control-Allow-Methods" = "'GET, POST, DELETE'" # remove or add HTTP methods as needed
}
}
############
Variables.tf 文件将是
# -----------------------------------------------------------------------------
# Variables: API Gateway
# -----------------------------------------------------------------------------
# var.api_id
variable "api_id" {
description = "API identifier"
}
# var.api_resource_id
variable "api_resource_id" {
description = "API resource identifier"
}
# -----------------------------------------------------------------------------
# Variables: CORS-related
# -----------------------------------------------------------------------------
# var.allow_headers
variable "allow_headers" {
description = "Allow headers"
type = list(string)
default = [
"Authorization",
"Content-Type",
"X-Amz-Date",
"X-Amz-Security-Token",
"X-Api-Key",
]
}
# var.allow_methods
variable "allow_methods" {
description = "Allow methods"
type = list(string)
default = [
"OPTIONS",
"HEAD",
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
]
}
# var.allow_origin
variable "allow_origin" {
description = "Allow origin"
type = string
default = "*"
}
# var.allow_max_age
variable "allow_max_age" {
description = "Allow response caching time"
type = string
default = "7200"
}
# var.allowed_credentials
variable "allow_credentials" {
description = "Allow credentials"
default = false
}
输出.tf
output "cors_resource_id" {
value = aws_api_gateway_resource.cors.id
}
然后就可以使用这个模块了
resource "aws_api_gateway_rest_api" "api" {
name = var.api_name
tags = var.tags
}
####CORS####
module "cors" {
source = "../api-gateway-cors"
api_id = aws_api_gateway_rest_api.api.id
api_resource_id = aws_api_gateway_rest_api.api.root_resource_id
}
############