3. API Gateway构建RESTful API

API Gateway 是 AWS 无服务器架构中面向客户端的统一入口。它负责接收 HTTP 请求、执行鉴权与校验、把请求转发给后端(通常是 Lambda),再把结果按约定格式返回。要真正把 API 做“对”,需要同时理解三件事:选哪种 API 类型、如何定义资源与方法、以及如何用阶段和阶段变量管理多环境。

一、三种 API 类型怎么选

API Gateway 提供 REST、HTTP 和 WebSocket 三类 API,它们的定位差异明显:

  • REST API:功能最全,支持 API Key、使用计划、请求验证、映射模板、缓存、WAF 集成、私有端点等。适合需要精细控制请求/响应转换、需要按用量计费或需要边缘优化的对外 API。
  • HTTP API:更轻量、更低延迟、更便宜,原生支持 JWT 授权和 CORS 配置,但不支持映射模板、请求验证、API Key 与使用计划。适合纯代理到 Lambda 或 HTTP 后端的简单场景。
  • WebSocket API:面向长连接双向通信,路由键由 $request.body.action 或 $connect/$disconnect 决定,适合聊天、实时推送、协同编辑。

本节以 REST API 为主线,因为它覆盖了题目要求的全部能力。若只是把请求原样转给 Lambda,HTTP API 往往是更优选择。

二、资源与方法定义

REST API 的核心模型是“资源树 + 方法”。资源对应 URL 路径,方法对应 HTTP 动词。例如要暴露一个订单查询接口,可以定义:

/orders            GET    列出订单
/orders            POST   创建订单
/orders/{orderId}  GET    查询单个订单
/orders/{orderId}  DELETE 删除订单

其中 {orderId} 是路径参数,API Gateway 会把它放进 event.pathParameters.orderId 传给 Lambda。方法上还可以配置请求参数校验:把 orderId 标记为必填,并限制为数字或 UUID 正则,这样非法请求在进入 Lambda 之前就被拒绝,既省成本又减少后端防御代码。

三、阶段、部署与阶段变量

REST API 的变更不会自动生效,必须“部署”到一个阶段(Stage)。阶段是 API 的一个快照加一组配置,常见做法是建 dev、test、prod 三个阶段,各自指向不同的 Lambda 别名或不同的后端地址。

阶段变量(Stage Variables)是阶段级别的键值对,可以在集成请求的 URI、Lambda 函数名、映射模板中通过 ${stageVariables.xxx} 引用。典型用法是让同一个 API 定义在不同阶段指向不同后端:

阶段 dev  : stageVariables.lambdaAlias = dev
阶段 prod : stageVariables.lambdaAlias = prod

集成 URI:
arn:aws:apigateway:cn-north-1:lambda:path/2015-03-31/functions/
arn:aws:lambda:cn-north-1:123456789012:function:orderService:${stageVariables.lambdaAlias}/invocations

这样切换环境只需改阶段变量,而不必复制整套 API。注意:使用阶段变量指向 Lambda 别名时,需要在 Lambda 上添加权限,允许 API Gateway 以该别名调用,否则会返回 500。

四、请求验证与映射模板

请求验证器(Request Validator)可以校验请求体是否符合模型(Model)、参数是否满足约束。开启后,不符合的请求直接返回 400,不会触发 Lambda。

映射模板(Mapping Template)使用 VTL(Velocity Template Language)在请求进入后端前重塑数据,或在响应返回客户端前重塑结果。例如把客户端传来的扁平 JSON 包装成 Lambda 期望的结构:

#set($inputRoot = $input.path('$'))
{
  "orderId": "$inputRoot.orderId",
  "source": "api-gateway",
  "stage": "$context.stage"
}

映射模板也常用于把 Lambda 返回的 JSON 转成纯文本、XML 或自定义错误结构。若不需要转换,选择“透传(proxy integration)”即可,此时 Lambda 必须返回 statusCode、headers、body 三要素。

五、与 Lambda 集成与 CORS

Lambda 集成分两种:Lambda 代理集成(Lambda Proxy)把整个请求原样交给 Lambda,由 Lambda 决定状态码和响应体,配置最简单;Lambda 自定义集成则配合映射模板做请求/响应转换,控制更细但配置更多。多数 REST API 场景推荐代理集成。

浏览器跨域调用时,需要配置 CORS。REST API 的 CORS 不是自动的,需要为每个资源添加 OPTIONS 方法,返回如下响应头:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET,POST,DELETE,OPTIONS
Access-Control-Allow-Headers: Content-Type,Authorization

如果使用代理集成,也可以在 Lambda 中统一返回这些头,但 OPTIONS 预检请求仍需 API Gateway 直接响应,否则预检会打到 Lambda 造成额外调用。

REST API 请求链路:客户端 → 阶段 → 资源/方法 → Lambda 浏览器 / App GET /orders/1001 阶段 Stage dev / test / prod 阶段变量 lambdaAlias 资源与方法 /orders GET POST /orders/{orderId} GET 请求验证 + 映射模板 Lambda orderService:${alias} CORS 预检 OPTIONS Access-Control-Allow-Origin / Methods / Headers 由 API Gateway 直接响应,不触发 Lambda 响应返回 statusCode + headers + body(代理集成)或经映射模板转换后返回 关键点: ① 阶段变量让同一 API 指向不同 Lambda 别名;② 请求验证在网关层拦截非法请求;③ 映射模板负责请求/响应重塑;④ CORS 预检由网关直接处理。

六、一个可复用的配置检查清单

把上面的要点整理成一份可直接对照的检查表,便于在创建或评审 REST API 时逐项确认:

检查项推荐做法判断依据
API 类型需要映射模板/请求验证/API Key 选 REST;纯代理选 HTTP功能需求清单
资源与方法路径参数用 {param},方法按语义选动词URL 可读性与 REST 规范
阶段至少 dev/prod 两阶段,各自独立部署环境隔离要求
阶段变量用 ${stageVariables.lambdaAlias} 指向别名切换环境不改 API 定义
请求验证对必填参数和请求体模型开启验证器非法请求返回 400 而非 500
映射模板仅在需要转换时使用,否则用代理集成后端期望的数据结构
CORS为每个资源添加 OPTIONS 方法并返回允许头浏览器预检通过
阶段变量引用 Lambda 别名时,务必在 Lambda 上执行 aws lambda add-permission 授权 API Gateway 调用该别名,否则集成会返回 500。这是最常见的“配置看起来对但调用失败”的原因。

掌握以上内容后,就可以用一套 API 定义覆盖多环境,并在网关层完成校验与转换,让 Lambda 专注于业务逻辑。实际落地时建议先用代理集成跑通链路,再按需引入映射模板和请求验证,避免一开始就陷入 VTL 的复杂度。