CloudFormation部署API Gateway异常:Stage配置错误及CORS问题求助
CloudFormation模板问题与CORS错误解答
问题背景
刚接触YAML编写与CloudFormation部署,构建的模板部署后出现以下问题:
- 预期创建
prod和dev两个API Gateway Stage,但实际仅生成dev和默认的Stage,无prod; - 浏览器调用API触发CORS错误,但Insomnia/Postman中可正常运行;
- 不理解
ProxyApiRoot和ProxyApiGreedy的作用,且移除该配置后部署结果无变化。
原YAML模板
AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: Storygraf backend API Globals: Function: Timeout: 3 Resources: ExpressApi: Type: AWS::Serverless::Api Properties: StageName: prod StageName: dev ExpressLambdaFunction: Type: AWS::Serverless::Function Properties: Environment: Variables: CodeUri: ./ Handler: lambda.handler MemorySize: 512 Runtime: nodejs14.x Timeout: 30 Events: ProxyApiRoot: Type: Api Properties: RestApiId: !Ref ExpressApi Path: / Method: ANY cors: true ProxyApiGreedy: Type: Api Properties: RestApiId: !Ref ExpressApi Path: /{proxy+} Method: ANY cors: true
1. 为什么只生成dev Stage,没有prod?
YAML语法中,同一个键重复定义时后定义的会覆盖前一个。你的ExpressApi资源里连续写了两次StageName:
Properties: StageName: prod StageName: dev
最终生效的只有最后一个dev,所以API Gateway只创建了dev Stage。而默认的Stage是SAM部署过程中自动生成的临时部署节点,并非你定义的正式Stage。
如果要同时创建prod和dev两个正式Stage,需要额外定义AWS::ApiGateway::Deployment和AWS::ApiGateway::Stage资源,示例如下:
Resources: # 保留原ExpressApi定义,移除重复的StageName ExpressApi: Type: AWS::Serverless::Api Properties: Name: StorygrafApi # 创建prod Stage的部署 ApiProdDeployment: Type: AWS::ApiGateway::Deployment DependsOn: - ProxyApiRoot - ProxyApiGreedy Properties: RestApiId: !Ref ExpressApi StageName: prod # 创建dev Stage的部署 ApiDevDeployment: Type: AWS::ApiGateway::Deployment DependsOn: - ProxyApiRoot - ProxyApiGreedy Properties: RestApiId: !Ref ExpressApi StageName: dev
2. ProxyApiRoot和ProxyApiGreedy是什么?
这是API Gateway的代理集成配置,用来把所有API请求转发到Lambda处理,适合Express这类Node.js框架的Serverless部署:
ProxyApiRoot:匹配根路径/的所有HTTP方法(ANY表示GET/POST/PUT等所有方法),将请求直接转发到Lambda;ProxyApiGreedy:匹配路径/{proxy+},其中{proxy+}是贪婪匹配规则,会捕获根路径之后的所有子路径(比如/api/users、/test/123等),并将这些请求转发到Lambda。
这种配置的好处是无需在CloudFormation中逐个定义API端点,所有路由逻辑都可以在Express代码中处理,和传统Express项目的路由写法一致。
3. Proxy配置会导致CORS问题吗?
Proxy配置本身不会直接引发CORS错误,问题出在CORS响应头的配置上:
- 浏览器会发送预检OPTIONS请求验证跨域权限,但Insomnia/Postman这类工具不会触发预检,所以能正常调用;
- 你在Api事件中设置的
cors: true,SAM只会帮你生成基础的OPTIONS响应头,但可能存在配置不全或和Express自身响应头冲突的情况; - 正确的做法是在Express代码中通过
cors中间件统一配置CORS规则,确保覆盖所有场景:
const express = require('express'); const cors = require('cors'); const app = express(); // 配置CORS,生产环境建议指定具体域名,而非* app.use(cors({ origin: 'https://your-frontend-domain.com', methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization'] })); // 其他路由逻辑...
同时可以移除Api事件中的cors: true,避免SAM自动生成的响应头和Express的配置冲突。
内容的提问来源于stack exchange,提问作者Joshua Foxworth
相关产品推荐
相关产品推荐

