使用 Serverless Framework 为 AWS Lambda 配置 HTTP API(API Gateway v2)事件:从 CORS、鉴权到自定义域名
本指南以 docs/sf/providers/aws/events/http-api.md 为骨架,系统讲解如何在 Serverless Framework 中通过 httpApi 事件把 AWS Lambda 函数暴露为 API Gateway v2(HTTP API)端点。你将掌握事件定义与参数语法、CORS 精细配置、JWT / Lambda(请求) / AWS IAM 三类授权器、访问日志、多服务复用 API、payload 版本选择以及自定义域名接入的完整步骤,并结合仓库中 packages/serverless/lib/plugins/aws/package/compile/events/http-api.js 的编译实现理解背后的 CloudFormation 生成逻辑。
背景:API Gateway v1 与 v2 的选择
API Gateway 提供两个版本部署 HTTP API:
- v1(REST API):功能最全的传统版本;
- v2(HTTP API):部署更快、运行成本更低,是新增服务时的推荐选择。
需要注意命名容易混淆:两个版本都支持部署任意类型的 HTTP API(REST、GraphQL 等)。本文档只讨论 v2 HTTP API,对应 httpApi 事件;若你希望使用 v1 REST API,请参考 API Gateway(REST API)事件指南。
在仓库源码中,httpApi 事件由 http-api.js 编译插件 实现,其 package:compileEvents 钩子依次执行 compileApi()、compileLogGroup()、compileStage()、compileAuthorizers()、compileEndpoints() 五个步骤(http-api.js 第 67-77 行),最终把配置翻译成 AWS::ApiGatewayV2::* 系列 CloudFormation 资源。
事件定义基础
httpApi 事件同时支持字符串缩写与对象完整写法两种形式:
functions:
simple:
handler: handler.simple
events:
- httpApi: 'PATCH /elo'
extended:
handler: handler.extended
events:
- httpApi:
method: POST
path: /post/just/to/this/path
simple 使用 'PATCH /elo' 将 method 与 path 写在一行;extended 显式拆分两个字段,语义完全等价。
从源码可以印证事件命名的严格性:编译插件中定义了合法方法集合 ANY / GET / POST / PUT / PATCH / OPTIONS / HEAD / DELETE,并通过两条正则分别校验「单方法缩写」和「方法 + 路径」两种字符串写法,不匹配即报配置错误(http-api.js 第 9-26 行)。
Catch-alls 通配
支持用 * 通配整个 API 或单个方法:
functions:
catchAllAny:
handler: index.catchAllAny
events:
- httpApi: '*'
catchAllMethod:
handler: handler.catchAllMethod
events:
- httpApi:
method: '*'
path: /any/method
httpApi: '*':捕获所有路径与所有方法(对应默认路由);method: '*'+ 指定path:只对该路径开放所有方法。
路径参数
HTTP API 路由天然支持 {param} 占位符,与 Lambda Proxy 集成一起使用时,参数值会出现在传给函数的事件对象中:
functions:
params:
handler: handler.params
events:
- httpApi:
method: GET
path: /get/for/any/{param}
端点超时与函数超时的关系
HTTP API 使用 API Gateway 的默认与最大超时 30 秒。因此务必将函数超时控制在 29 秒以内,否则会出现 Lambda 实际调用成功、但客户端收到 503 状态码的现象——这正是 API Gateway 在 30 秒处主动截断等待的典型表现。
CORS 配置
HTTP API 允许在 provider.httpApi.cors 下配置对所有已配置端点全局生效的 CORS 响应头。
一键开启默认配置
provider:
httpApi:
cors: true
默认会输出如下请求头(该默认值在源码中硬编码于 http-api.js 第 34-45 行):
| Header | Value |
|---|---|
| Access-Control-Allow-Origin | * |
| Access-Control-Allow-Headers | Content-Type, X-Amz-Date, Authorization, X-Api-Key, X-Amz-Security-Token, X-Amz-User-Agent, X-Amzn-Trace-Id |
| Access-Control-Allow-Methods | OPTIONS, (...all defined in endpoints) |
精细自定义
如需微调,可逐项配置:
provider:
httpApi:
cors:
allowedOrigins:
- https://url1.com
- https://url2.com
allowedHeaders:
- Content-Type
- Authorization
allowedMethods:
- GET
allowCredentials: true
exposedResponseHeaders:
- Special-Response-Header
maxAge: 6000 # In seconds
源码层面,compileApi() 会把上述字段映射为 AWS::ApiGatewayV2::Api 的 CorsConfiguration(AllowCredentials、AllowHeaders、AllowMethods、AllowOrigins、ExposeHeaders、MaxAge),并在未配置 cors 时不生成该块(http-api.js 第 170-182 行)。
JWT Authorizers(JWT 授权器)
JWT 授权器是限制 HTTP API 端点访问的方式之一。要让 serverless.yml 中配置的端点启用鉴权,分两步:
1. 在 provider.httpApi.authorizers 定义授权器
provider:
httpApi:
authorizers:
someJwtAuthorizer:
type: jwt
identitySource: $request.header.Authorization
issuerUrl: https://cognito-idp.${region}.amazonaws.com/${cognitoPoolId}
audience:
- ${client1Id}
- ${client2Id}
典型场景是把 Amazon Cognito 用户池作为签发方:issuerUrl 指向用户池的签发地址,audience 列出允许的应用客户端 ID,identitySource 声明从请求头 Authorization 读取令牌。
2. 在端点级引用授权器并声明 OAuth scopes
functions:
someFunction:
handler: index.handler
events:
- httpApi:
method: POST
path: /some-post
authorizer:
name: someJwtAuthorizer
scopes: # Optional
- user.id
- user.email
name 关联到 provider 级定义的授权器;scopes 可选,用于限定该路由所需 OAuth 作用域。编译插件在 compileAuthorizers() 中为每个授权器生成 AWS::ApiGatewayV2::Authorizer 资源(类型为 JWT 或 REQUEST),并将 identitySource 规范化为数组后写入(http-api.js 第 266-285 行)。
Lambda(Request)Authorizers(请求授权器)
除 JWT 外,还可以用自定义 Lambda 函数充当授权器。此类授权器 type 固定为 request,其来源函数既可以来自当前服务,也可以来自服务之外。
使用本服务内的函数作为授权器
需先在 provider 级按函数名引用授权器,再在端点中引用它:
provider:
name: aws
httpApi:
authorizers:
customAuthorizer:
type: request
functionName: authorizerFunc
functions:
hello:
handler: handler.hello
events:
- httpApi:
method: get
path: /hello
authorizer:
name: customAuthorizer
authorizerFunc:
handler: authorizer.handler
使用服务外部的函数作为授权器
若授权函数属于其他部署,直接传其 ARN:
provider:
name: aws
httpApi:
authorizers:
customAuthorizer:
type: request
functionArn: arn:aws:lambda:us-east-1:11111111111:function:external-authorizer
functions:
hello:
handler: handler.hello
events:
- httpApi:
method: get
path: /hello
authorizer:
name: customAuthorizer
授权器完整配置项
type:自定义 Lambda 授权器必须设为request。name:可选,自定义授权器名称。functionName:本服务内作为授权器使用的函数名;与functionArn互斥。functionArn:授权函数的 ARN,支持 CloudFormation 内建函数(如Fn::ImportValue);与functionName互斥。resultTtlInSeconds:可选,授权结果缓存 TTL,取值 0(不缓存)到 3600(1 小时)。设为非 0 时必须同时定义identitySource(它同时充当授权结果缓存的键)。enableSimpleResponses:可选,是否让授权函数以「简单格式」返回授权响应,默认false。payloadVersion:可选,发送给授权函数的 payload 版本,默认'2.0'。identitySource:可选,一个或多个请求参数映射表达式(如$request.header.Auth),授权器会校验其非空;当resultTtlInSeconds非 0 时为必填。managedExternally:可选,标记授权函数是否完全由外部管理(例如位于其他 AWS 账户)。设为true时会跳过为该授权函数创建 Lambda 权限资源。
完整配置示例:
provider:
name: aws
httpApi:
authorizers:
customAuthorizer:
type: request
functionName: authorizerFunc # Mutually exclusive with `functionArn`
functionArn: arn:aws:lambda:us-east-1:11111111111:function:external-authorizer # Mutually exclusive with `functionName`
name: customAuthorizerName
resultTtlInSeconds: 300
enableSimpleResponses: true
payloadVersion: '2.0'
identitySource:
- $request.header.Auth
- $request.header.Authorization
managedExternally: true # 仅当使用外部函数时适用,用于阻止创建权限资源
注意 functionName 与 functionArn 两个字段虽然同框出现,但语义上互斥,实际配置二选一即可。
AWS IAM 授权
也可以借助 AWS IAM 策略来保护 HTTP API 端点:把事件上的 authorizer 设为 type: aws_iam 即可。此后只有具备调用该 API 权限的 IAM 身份(如使用 SigV4 签名)才能访问:
provider:
name: aws
functions:
hello:
handler: handler.hello
events:
- httpApi:
method: get
path: /hello
authorizer:
type: aws_iam
Access logs(访问日志)
注意: 如果完全没有设置 logs.httpApi,HTTP API 日志将保持关闭。
在 provider 中开启后即可启用部署阶段的访问日志:
provider:
logs:
httpApi: true
默认日志格式为:
{
"requestId": "$context.requestId",
"ip": "$context.identity.sourceIp",
"requestTime": "$context.requestTime",
"httpMethod": "$context.httpMethod",
"routeKey": "$context.routeKey",
"status": "$context.status",
"protocol": "$context.protocol",
"responseLength": "$context.responseLength"
}
可借助 format 覆盖为自定义格式(支持 $context.* 变量组合):
provider:
logs:
httpApi:
format: '{ "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime" }'
日志变量详情参见 AWS 官方「HTTP API 日志变量」文档。实现层面,compileLogGroup() 会为访问日志创建 AWS::Logs::LogGroup(并继承 provider 的日志保留天数与数据保护策略设置,http-api.js 第 188-211 行);compileStage() 中则将格式与日志组 ARN 写入 AWS::ApiGatewayV2::Stage 的 AccessLogSettings(http-api.js 第 233-244 行)。
在多个服务间复用 HTTP API
可以将当前服务配置的端点挂载到外部创建的 HTTP API,只需在 provider 提供 API id:
provider:
httpApi:
id: xxxx # id of externally created HTTP API to which endpoints should be attached.
由于 id 本身可能是由其他 CloudFormation 栈导出后由 Fn::ImportValue 引用得到:
provider:
httpApi:
id:
Fn::ImportValue: xxxx # 代表外部 HTTP API id 的导出值名称
约束:使用外部 HTTP API 时,不再创建 API 与 Stage 资源,因此不支持扩展 CORS、访问日志或授权器等依赖 API/Stage 的配置。源码中 compileApi() 与 compileStage() 遇到 this.config.id 都会提前返回(http-api.js 第 157 行、第 213 行)。
HTTP API URL
部署带 httpApi 事件的函数后,serverless deploy 与 serverless info 的输出中会展示 HTTP API 的 URL。该 URL 同时以 HttpApiUrl 输出的形式导出为 CloudFormation Output——compileStage() 通过 Ref API id 拼出形如 https://{apiId}.execute-api.{region}.{suffix} 的地址并写入 HttpApiId、HttpApiUrl 两个输出(http-api.js 第 245-264 行)。你可以在其它栈中 Fn::ImportValue 这个导出值使用。
共享 Authorizer(针对外部 HTTP API)
对于复用的外部 HTTP API,可以类似 REST API 那样使用共享授权器:先引用其 authorizerId(可硬编码或用 Ref 指向自定义创建的 AWS::ApiGatewayV2::Authorizer 资源),并在事件上声明授权器 type 与可选 scopes:
httpApi:
id: xxxx # Required
functions:
createUser:
...
events:
- httpApi:
path: /users
...
authorizer:
# Type of referenced authorizer
type: jwt
# Provide authorizerId
id:
Ref: ApiGatewayAuthorizer # or hard-code Authorizer ID
scopes: # Optional - List of Oauth2 scopes
- myapp/myscope
deleteUser:
...
events:
- httpApi:
path: /users/{userId}
...
authorizer:
# Type of referenced authorizer
type: jwt
# Provide authorizerId
id:
Ref: ApiGatewayAuthorizer # or hard-code Authorizer ID
scopes: # Optional - List of Oauth2 scopes
- myapp/anotherscope
resources:
Resources:
ApiGatewayAuthorizer:
Type: AWS::ApiGatewayV2::Authorizer
Properties:
ApiId:
Ref: YourApiGatewayName
AuthorizerType: JWT
IdentitySource:
- $request.header.Authorization
JwtConfiguration:
Audience:
- Ref: YourCognitoUserPoolClientName
Issuer:
Fn::Join:
- ""
- - "https://cognito-idp."
- "${opt:region, self:provider.region}"
- ".amazonaws.com/"
- Ref: YourCognitoUserPoolName
当使用共享的 Lambda 自定义授权器时,把 type 设为 request 即可;scopes 仅在 JWT 场景使用。
Event / Payload 格式(1.0 与 2.0)
HTTP API 只提供 Lambda 的 proxy 集成选项——事件对象中携带请求头、查询字符串等完整 HTTP 上下文。该事件存在 1.0 与 2.0 两种格式,默认 2.0,可通过 payload 降级为 1.0。可在 provider 层全局配置:
provider:
httpApi:
payload: '1.0'
也可在函数级通过 httpApi.payload 单独指定,优先级高于 provider 层配置:
functions:
hello:
handler: index.handler
httpApi:
payload: '1.0'
events:
- httpApi:
path: /hello
method: GET
源码按「函数级优先于 provider 级、都没有则回落默认 '2.0'」的顺序解析版本(http-api.js 第 736 行),随后通过 Lambda 目标 ARN 与 resolveLambdaTarget() 关联到函数。
Detailed Metrics(详细指标)
开启后即可在 CloudWatch 中对 HTTP API 建立监控与告警:
provider:
httpApi:
metrics: true
该开关会落到 Stage 的 DefaultRouteSettings.DetailedMetricsEnabled(http-api.js 第 218-220 行)。
Tags 标签
设置 provider.httpApi.useProviderTags: true 后,provider.tags 定义的所有标签都会应用到 API Gateway 及其 Stage:
provider:
tags:
project: myProject
httpApi:
useProviderTags: true
上例中 project: myProject 会被同时打到 API Gateway 与 API Gateway Stage。注意:如果 API Gateway 上存在由 Serverless Framework 之外的途径添加的旧标签,这些标签会在部署时被清除。另请注意,当前仓库的实现中 useProviderTags 已被标记为「不再生效」——provider 标签默认就会应用于 HTTP API,配置里可以安全移除该属性并关注框架的弃用告警(http-api.js 第 56-65 行)。
禁用默认端点
默认情况下,客户端可用 https://{api_id}.execute-api.{region}.amazonaws.com 端点调用 API。若要求客户端必须通过自定义域名访问,可禁用默认端点:
provider:
httpApi:
disableDefaultEndpoint: true
该配置在 compileApi() 中映射为 AWS::ApiGatewayV2::Api 的 DisableExecuteApiEndpoint 属性(http-api.js 第 161-164 行)。
服务命名(Naming)
默认情况下 HTTP API 名称为 ${stage}-${service};如需调整可以启用:
provider:
httpApi:
shouldStartNameWithService: true
启用后命名顺序变为 ${service}-${stage},便于资源按服务名聚合管理。
自定义域名接入
API Gateway 为 HTTP API 生成的 URL 形如:
https://<random>.execute-api.<region>.amazonaws.com/
可以通过以下三步替换为自有域名:
Step 1:在 AWS ACM 创建 HTTPS 证书
- 打开 AWS Certificate Manager(ACM);
- 切换到应用所在区域;
- 点击 "Request a certificate",选择 "Request a public certificate" 继续;
- 填入域名后继续;
- 选择域名校验方式:
- 邮箱校验(Email validation):需点击发送至
admin@your-domain.com邮件中的链接; - DNS 校验(Domain validation):需在 DNS 配置中新增 CNAME 记录;
- 邮箱校验(Email validation):需点击发送至
- 完成上述任一校验。
Step 2:在 API Gateway 配置自定义域名
- 打开 API Gateway 的 "Custom Domain"(域名)管理页面;
- 切换到应用所在区域;
- 点击 "Create";
- 输入域名并选择上一步创建的证书,确认信息;
- 域名创建完成后,进入 "API mappings" 页签;
- 点击 "Configure API mappings" → "Add new mapping";
- 选择你的 HTTP API 与
$defaultStage; - 点击 "Save"。
Step 3:配置域名的 DNS
- 若使用 Route53:
- 打开对应的 Hosted Zone;
- 点击 "Create record";
- "Record type" 选 "A";
- "Route traffic to" 选择 "Alias",再选中你的 API Gateway;
- 完成记录创建。
- 若使用其他域名注册商:
- 打开自定义域名名称下的 "Configurations" 页签;
- 记录 "API Gateway domain name"(形如
d-1234567890.execute-api.us-east-1.amazonaws.com); - 创建一条 CNAME 记录,把自有域名指向该 API Gateway 域名。
自定义域名配置完成后,即可按上文「禁用默认端点」一节强制走自定义域名:
provider:
httpApi:
disableDefaultEndpoint: true
小结
httpApi 事件把「声明式路由配置 → CloudFormation 资源」的转换封装在 编译插件 内部,覆盖 API、Stage、日志组、授权器与路由的全部编排,并配套了完整的单元测试(见 http-api.test.js 测试)。从简单的 'PATCH /elo' 缩写、Catch-all 通配与路径参数,到 CORS、三类授权器、访问日志、payload 版本、指标、标签、共享 API 与自定义域名,以上配置均可在单个 serverless.yml 中完成,适合直接作为生产环境的部署参照。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00