3. API Gateway构建RESTful API

在 Serverless 架构中,API Gateway 是客户端与后端计算之间的“门面”。它把 HTTP 请求翻译成 Lambda 调用,同时承担路由、鉴权、校验、限流和版本发布等职责。本节围绕一条真实的 RESTful API 展开:一个“订单查询服务”,包含 GET /orders(列表)与 GET /orders/{id}(详情)两个资源路径,后端由 Lambda 处理。我们将依次说明资源与方法定义、阶段与部署、请求验证与转换、限流与 API 密钥,以及与 Lambda 的集成方式。

资源与方法:REST API 的骨架

API Gateway 的 REST API 采用“资源树 + 方法”的模型。资源(Resource)对应 URL 路径,方法(Method)对应 HTTP 动词。创建时先建根资源 /,再逐级创建子资源。例如先建 /orders,再在其下建路径参数资源 /{id},其中花括号表示占位符,实际请求 /orders/1001 时,id 会被解析为路径参数。

每个资源上挂载方法。以 GET /orders/{id} 为例,需要定义:方法请求(Method Request)——声明入参、授权方式;集成请求(Integration Request)——声明如何把请求转发给 Lambda;集成响应(Integration Response)——把 Lambda 返回映射为 HTTP 响应;方法响应(Method Response)——声明状态码与响应头。这四层结构是 REST API 的核心,理解它才能正确配置转换与校验。

路径参数需要在方法请求中显式声明。例如在 GET /orders/{id} 的方法请求里添加名为 id 的路径参数,并可在请求验证器中约束其格式。若未声明,集成模板中引用 $input.params('id') 将取不到值。

阶段与部署:让 API 可访问

API 定义完成后并不会自动对外生效,必须“部署”到某个阶段(Stage)。阶段是 API 的独立快照,拥有自己的 URL、变量和限流配置。常见做法是建立 dev、test、prod 三个阶段,分别指向不同后端或使用不同参数。

部署后得到调用地址,形如:

https://{api-id}.execute-api.{region}.amazonaws.com/{stage}/orders/1001

阶段变量(Stage Variables)用于在不同阶段切换后端,例如把 Lambda 别名设为 ${stageVariables.lambdaAlias},在 dev 阶段填 dev、prod 阶段填 prod,从而让同一份 API 定义指向不同版本的 Lambda。此外,还可以启用阶段缓存、设置日志级别与访问日志,便于排障。

每次修改资源、方法或集成后,都必须重新部署到目标阶段,否则线上行为不会变化。这是初学者最常见的“改了没生效”原因。

请求验证与转换

请求验证器(Request Validator)可以在请求到达 Lambda 之前拦截非法请求,减少无效调用。它支持校验必填参数、查询字符串和请求体模型。例如为 GET /orders 定义查询参数 status(可选)与 limit(必填,整数),并创建 JSON Schema 模型约束请求体。若客户端缺少 limit,API Gateway 直接返回 400,不会触发 Lambda。

转换则通过映射模板(Mapping Template)完成。集成请求使用 Velocity 模板语言(VTL),把 HTTP 请求重塑为 Lambda 期望的事件结构。例如把路径参数与查询参数组装成 JSON:

{
  "orderId": "$input.params('id')",
  "status": "$input.params('status')",
  "limit": $input.params('limit')
}

集成响应同样可用模板把 Lambda 的返回映射为指定状态码与响应体。例如 Lambda 返回 {"code":404,"message":"not found"},可通过正则匹配 code 映射为 HTTP 404。这样后端逻辑与 HTTP 语义解耦,前端拿到的始终是规范的 REST 响应。

限流与 API 密钥

限流(Throttling)保护后端不被突发流量击垮。API Gateway 提供账户级与阶段级限流,核心参数是速率(rate,每秒请求数)与突发(burst,令牌桶容量)。例如设置 rate=100、burst=200,表示稳态每秒 100 个请求,允许短时突增到 200。方法级还可单独覆盖,例如对写操作设置更严格的限流。

API 密钥(API Key)用于识别调用方并配合使用计划(Usage Plan)实施配额。使用计划可绑定阶段与方法,设置每日/每周配额和限流。密钥本身不是强鉴权手段,应与 IAM 授权、Lambda 授权方或 Cognito 结合使用。典型流程是:创建密钥 → 创建使用计划 → 关联阶段 → 把密钥分发给客户端,客户端在请求头 x-api-key 中携带。

与 Lambda 集成

集成类型选择 AWS_PROXY(Lambda 代理集成)最为常用:API Gateway 把完整请求(含路径、查询、头、体)作为事件传给 Lambda,Lambda 返回 statusCode、headers、body 三要素,API Gateway 原样转成 HTTP 响应。这种方式无需手写映射模板,灵活度高。若需要精细控制请求/响应格式,则使用非代理集成并配合映射模板。

Lambda 需要被授予 lambda:InvokeFunction 权限,通常由 API Gateway 自动创建资源策略完成。若使用阶段变量指向别名,权限需覆盖对应别名。下面是一个代理集成的 Lambda 处理示例(Node.js):

exports.handler = async (event) => {
  const id = event.pathParameters?.id;
  if (!id) {
    return { statusCode: 400, body: JSON.stringify({ message: 'missing id' }) };
  }
  const order = await getOrder(id); // 假设的查询函数
  if (!order) {
    return { statusCode: 404, body: JSON.stringify({ message: 'not found' }) };
  }
  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(order)
  };
};

部署后可用 curl 验证:curl -H "x-api-key: xxx" https://.../prod/orders/1001。若返回 403 且提示 Forbidden,通常是密钥缺失或使用计划未关联;若返回 502,多为 Lambda 返回格式不符合代理集成要求,需检查 statusCode 是否为数字、body 是否为字符串。

REST API 请求链路:客户端 → API Gateway → Lambda 客户端 GET /orders/1001 x-api-key: xxx API Gateway(阶段 prod) 资源树 /orders /orders/{id} 方法 GET 方法请求 / 响应 集成请求 / 响应 请求验证器 必填参数 / 模型 非法 → 400 映射模板 VTL 请求 / 响应转换 $input.params() 限流 rate=100 / burst=200 | API 密钥 + 使用计划 超限 → 429 Too Many Requests 部署到阶段 prod | 阶段变量 lambdaAlias=prod Lambda AWS_PROXY 集成 返回 statusCode/body 200 OK / 400 / 404 / 429 响应返回客户端

把上述环节串起来看:资源与方法定义 API 的“形状”,阶段与部署让它“上线”,验证与转换保证“输入规范、输出标准”,限流与密钥控制“谁能调、调多快”,Lambda 集成则提供“业务逻辑”。五者协同,才构成一条可运维、可扩展的 RESTful API。实际项目中建议先用代理集成快速打通链路,再按需引入验证器、映射模板和使用计划,避免一开始就过度配置。