Pulumi配置AWS API Gateway Response未生效,CORS头缺失问题
使用Pulumi创建代理Lambda后端的AWS API Gateway,Web前端调用该网关,多数场景下由Lambda处理CORS。但当API密钥的Usage Plan配额超出时,Gateway返回429响应却不带CORS头,导致前端无法准确判断问题,无法显示专属的“服务器过载”错误,只能显示通用提示。
尝试通过Pulumi配置Gateway Response来添加CORS头,涵盖QUOTA_EXCEEDED、THROTTLED等多种响应类型,代码如下:
addGatewayResponse(restApi.api.id, "429", "QUOTA_EXCEEDED"); addGatewayResponse(restApi.api.id, "429", "THROTTLED"); addGatewayResponse(restApi.api.id, "403", "INVALID_API_KEY"); addGatewayResponse(restApi.api.id, "403", "MISSING_AUTHENTICATION_TOKEN"); addGatewayResponse(restApi.api.id, "404", "RESOURCE_NOT_FOUND"); addGatewayResponse(restApi.api.id, "400", "DEFAULT_4XX"); addGatewayResponse(restApi.api.id, "500", "DEFAULT_5XX"); function addGatewayResponse( restApiId: pulumi.Output<string>, statusCode: string, responseType: string ) { new aws.apigateway.Response(`${name}-GatewayResponse-${responseType}`, { restApiId: api.api.id, responseType, statusCode, responseTemplates: { "application/json": JSON.stringify({ message: "$context.error.messageString", type: "$context.error.responseType", statusCode, resourcePath: "$context.resourcePath", }), }, responseParameters: { "gatewayresponse.header.Access-Control-Allow-Origin": "'*'", "gatewayresponse.header.Access-Control-Allow-Headers": "'*'", "gatewayresponse.header.Access-Control-Allow-Methods": "'*'", }, }); }
已完全销毁并重建栈,控制台显示配置符合预期,但测试时(省略API密钥或设置低配额),curl返回的429响应无CORS头:
< HTTP/2 429 < date: Thu, 27 Oct 2022 22:30:31 GMT < content-type: application/json < content-length: 28 < x-amzn-requestid: xxx < x-amzn-errortype: LimitExceededException < x-amz-apigw-id: xxx < * Connection #0 to host xxx.execute-api.xxx.amazonaws.com left intact {"message":"Limit Exceeded"}
Web端fetch抛出“TypeError: NetworkError when attempting to fetch resource.”错误,无法获取响应状态码。直接调用阶段的Invoke URL,网关已改为区域型以避开CloudFront,正常请求可正常工作,Gateway Response配置似乎完全未生效。
1. 修复变量引用错误
你的addGatewayResponse函数接收了restApiId参数,但实际创建aws.apigateway.Response时硬编码使用了api.api.id,如果api并非当前目标REST API的实例引用,会导致Gateway Response绑定到错误的API上,自然无法生效。修改函数内的restApiId为传入的参数:
function addGatewayResponse( restApiId: pulumi.Output<string>, statusCode: string, responseType: string ) { new aws.apigateway.Response(`${name}-GatewayResponse-${responseType}`, { restApiId: restApiId, // 替换原有的api.api.id responseType, statusCode, responseTemplates: { "application/json": JSON.stringify({ message: "$context.error.messageString", type: "$context.error.responseType", statusCode, resourcePath: "$context.resourcePath", }), }, responseParameters: { "gatewayresponse.header.Access-Control-Allow-Origin": "'*'", "gatewayresponse.header.Access-Control-Allow-Headers": "'*'", "gatewayresponse.header.Access-Control-Allow-Methods": "'*'", }, }); }
2. 确保API部署依赖Gateway Response
API Gateway的配置变更需要通过部署才能生效,需确保你的API部署资源依赖于所有Gateway Response资源,这样Pulumi会先创建Gateway Response再部署API,保证配置被正确应用。可以通过dependsOn属性添加依赖:
// 假设你的部署资源定义如下,添加dependsOn const deployment = new aws.apigateway.Deployment(`${name}-deployment`, { restApi: restApi.api, stageName: "prod", // 你的阶段名 }, { dependsOn: [ // 列出所有Gateway Response实例,或通过数组收集所有addGatewayResponse创建的资源 ], });
3. 验证响应类型与实际匹配
AWS API Gateway针对配额超限返回的响应类型确实是QUOTA_EXCEEDED,但可以通过CloudWatch日志查看$context.error.responseType的实际值,确认是否和你配置的响应类型一致,避免因类型拼写或匹配问题导致配置不生效。
4. 补充预检请求的CORS处理(可选)
如果前端发送OPTIONS预检请求时遇到错误,虽然DEFAULT_4XX已覆盖大部分场景,但可以单独针对OPTIONS方法配置对应的Gateway Response,确保预检请求的错误响应也带有CORS头。
完成上述修改后,重新部署栈并测试,此时429等错误响应应会包含CORS头,前端可正常获取响应状态码并显示专属错误提示。
内容的提问来源于stack exchange,提问作者Dave

