在 AWS Lambda 上托管 Scalar API Reference:Scalar.Aws.Lambda 集成实战指南
2026/9/15 5:42:39 网站建设 项目流程

在 AWS Lambda 上托管 Scalar API Reference:Scalar.Aws.Lambda 集成实战指南

【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar

Scalar.Aws.Lambda是 Scalar 官方 .NET 集成家族中的一员,它让你可以在由Amazon API Gateway HTTP API(payload format 2.0)托管的 AWS Lambda 函数内部,直接渲染出 Scalar API Reference 交互式文档。它同时提供零依赖注入(zero-DI)的静态工厂入口与标准 DI 注册入口,并与Scalar.Azure.Functions共享同一套无服务器渲染内核。读完本文,你将掌握从安装、双入口选型、API Gateway 路由声明到 Stage 前缀处理、OpenAPI 文档挂载与既有限制规避的完整落地路径。

1. 从变更记录看这个集成的诞生

在 integrations/dotnet/aws-lambda/CHANGELOG.md 中,Scalar.Aws.Lambda的演进清晰可循:

  • 0.1.0:首次引入该集成,用于渲染由 Amazon API Gateway HTTP API(payload format 2.0)前置的 AWS Lambda 函数中的 Scalar API Reference。
  • 0.2.0:正式补充双入口支持——零 DI 静态工厂ScalarApiReferenceHandler.Create与 DI 注册服务AddScalarApiReference/IScalarApiReference
  • 同版本内还完成了一项重要的架构调整:原本支撑Scalar.Azure.Functions托管无关请求处理器(request processor)、渲染结果(render result)与静态资源表(static-asset table)被下沉到共享工程,并通过新的SCALAR_SERVERLESS编译常量复用,Scalar.AspNetCoreScalar.AspireScalar.Azure.Functions均无公开 API 与行为变化。

也就是说,AWS Lambda 与 Azure Functions 两条无服务器集成线共享同一套渲染内核,这正是Scalar.Aws.Lambda可以做到“行为与 Azure 集成镜像一致”的底层原因。源码层面,该常量的生效位置在 Scalar.Aws.Lambda.csproj 的DefineConstantsSCALAR_AWS_LAMBDA;SCALAR_SERVERLESS),共享代码则通过<Compile Include="../../../shared/src/Scalar.Shared/**/*.cs" ...>直接编译进本程序集。

[!NOTE] 本集成仅支持 API Gateway HTTP API。REST API(payload format 1.0)、Application Load Balancer 与 Lambda Function URLs 不在当前支持范围内,详见下文 第 8 节。

2. 安装

在 Lambda 函数工程中执行:

dotnet add package Scalar.Aws.Lambda

从 Scalar.Aws.Lambda.csproj 可以看到,该包的目标框架为net8.0;net9.0;net10.0,依赖Amazon.Lambda.CoreAmazon.Lambda.APIGatewayEventsMicrosoft.Extensions.DependencyInjection.AbstractionsMicrosoft.Extensions.Options。静态资源(scalar.jsfavicon.svg等)以 EmbeddedResource 形式随包分发,Release 构建下默认使用 gzip 压缩版本,Debug 下使用未压缩版本,无需额外部署静态文件。

3. 两个入口:零 DI 静态工厂与 DI 注册服务

该包的两个入口共享同一套实现(ScalarApiReference),选择依据是你函数的托管方式。

Option A — 零 DI 静态工厂

适用于无依赖注入容器的普通 Lambda 函数。ScalarApiReferenceHandler.Create(...)返回一个可直接作为 Lambda 入口使用的Func<APIGatewayHttpApiV2ProxyRequest, ILambdaContext, Task<APIGatewayHttpApiV2ProxyResponse>>委托:

using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.RuntimeSupport; using Amazon.Lambda.Serialization.SystemTextJson; using Scalar.Aws.Lambda; var handler = ScalarApiReferenceHandler.Create(options => { options.Title = "My API"; }); await LambdaBootstrapBuilder.Create<APIGatewayHttpApiV2ProxyRequest, APIGatewayHttpApiV2ProxyResponse>(handler, new DefaultLambdaJsonSerializer()) .Build() .RunAsync();

从源码看,ScalarApiReferenceHandler.Create 内部构造了一个StaticOptionsSnapshot——一个实现IOptionsSnapshot<ScalarOptions>的最小适配器,它在每次访问时都构建全新的ScalarOptions实例,从而模拟 DI 路径中IOptionsSnapshot的按请求生命周期,保证两次调用之间不会串状态。

Option B — 依赖注入

适用于使用Amazon.Lambda.RuntimeSupport泛型宿主托管 Lambda 的场景:

using Microsoft.Extensions.DependencyInjection; using Scalar.Aws.Lambda; var services = new ServiceCollection(); services.AddScalarApiReference(options => { options.Title = "My API"; }); await using var provider = services.BuildServiceProvider(); // IScalarApiReference 注册为 Scoped,请按 Lambda + DI 的标准实践,每次调用创建独立 scope。 using var scope = provider.CreateScope(); var scalar = scope.ServiceProvider.GetRequiredService<IScalarApiReference>(); var response = await scalar.HandleAsync(request, context);

AddScalarApiReference 的实现做了两件事:始终注册IOptionsSnapshot<ScalarOptions>基础设施(即使未传入配置回调),并将IScalarApiReference注册为Scoped服务。因此务必避免从根 provider 直接解析,应遵循“每次调用新建 scope”的 Lambda 惯例。

两个入口的等价性有测试保障:ScalarApiReferenceHandlerTests.cs 中的Create_And_Di_ShouldProduceIdenticalResponses_ForSameInput对同一输入分别走两个入口,断言StatusCodeBodyIsBase64Encoded完全一致。

4. 声明 API Gateway 路由:{proxy+}贪婪参数

Scalar 需要接管某一路径下的所有请求,因此必须使用{proxy+}贪婪路径参数(类似 ASP.NET Core 的 catch-all 路由),并为裸索引路径单独声明一条路由。以 SAM 模板为例:

Events: ScalarIndex: Type: HttpApi Properties: Path: /scalar Method: GET ScalarProxy: Type: HttpApi Properties: Path: /scalar/{proxy+} Method: ANY

仓库自带的 playground/template.yaml 给出了完整可运行的模板(含Timeout: 10MemorySize: 256dotnet10运行时等 Globals 配置),并导出ScalarApiUrl输出便于直接访问验证。

路由语义

根据 docs/http-api-model.md 中描述的{proxy+}模型:

请求含义
GET /scalarGET /scalar/渲染默认文档的参考索引页
GET /scalar/v3渲染v3文档的参考索引页
GET /scalar/scalar.jsGET /scalar/scalar.aws.lambda.jsGET /scalar/favicon.svg提供内嵌的静态资源

实现上,ScalarApiReference.HandleAsync 直接从request.PathParameters["proxy"]读取路径余量(RouteRemainderKey = "proxy"),交由共享的ScalarRequestProcessor.Process(...)(位于 integrations/dotnet/shared/src/Scalar.Shared/Rendering/ScalarRequestProcessor.cs)解析文档名与静态资源。

[!NOTE] 若PathParameters完全不存在(例如函数被直接调用而未经过 API Gateway 代理集成),请求会被当作索引请求处理而不是抛异常,这也被测试覆盖。

5. 指向 OpenAPI 文档

默认情况下,Scalar 会在相对参考页的openapi/{documentName}.json路径查找 OpenAPI 文档。也就是说,你需要把你的文档暴露在openapi/v1.json(默认文档名v1)这个路由上,或者改变模式:

options.AddDocument("v1", routePattern: "openapi/v1.json");

测试 ScalarApiReferenceHandlerTests.cs 验证了默认行为:请求/scalar/时响应体中包含openapi/v1.json;而请求/scalar/v3后再请求/scalar/,响应中不会再出现openapi/v3.json——Create_ShouldNotLeakDocumentState_AcrossInvocations这个回归测试专门保证了静态工厂每次调用都拿到全新的ScalarOptions,避免前一次请求设置的文档状态泄漏到下一次调用。

6. Stage 与路由前缀:自动检测与手动覆盖

API Gateway HTTP API 会把命名 stage 作为路径段嵌入RawPath,但特殊的$defaultstage 不会。Scalar.Aws.Lambda的行为如下:

StageGET /scalar/RawPath行为
$default/scalar/不剥离任何前缀
prod/prod/scalar/自动检测prod并从相对 URL 中剥离

实现位于 ScalarApiReference.ApplyRoutePrefix:当ScalarOptions.RoutePrefix尚未被显式设置时,读取request.RequestContext.Stage,若为非空且不等于$default,则把 stage 名折入RoutePrefix。这与 ScalarOptions.AwsLambda.cs 中RoutePrefix的文档描述一致——它镜像了 Azure Functions 集成把host.jsonroutePrefix折入同一选项的做法。

对应测试Create_ShouldAutoDetectStage_LikeDiEntryPoint(ScalarApiReferenceHandlerTests.cs)验证了在prodstage 下渲染出的 HTML 引用'/scalar/'而非'/prod/scalar/'

特殊情况:如果你使用自定义域名(custom domain)的 base path mapping,该前缀不会反映在RequestContext.Stage中,此时必须显式设置:

options.RoutePrefix = "my-base-path";

7. HTTP 事件模型与响应细节

请求头处理

HTTP API 会把 header 名转为小写,并在headers字段中用逗号合并重复头(没有 payload format 1.0 那样的multiValueHeaders)。Scalar.Aws.Lambda读取Accept-EncodingIf-None-Match大小写不敏感(见 ScalarApiReference.GetHeader),因此无论 API Gateway 小写化还是直接测试调用时的大写形式,都能正确处理。

响应体编码

APIGatewayHttpApiV2ProxyResponse.IsBase64Encoded仅在响应体为 gzip 压缩的二进制静态资源时为true;HTML 页面与未压缩静态资源以普通 UTF-8 文本返回,IsBase64Encoded = false

BuildResponseAsync 完整地实现了状态码协商:

  • 302RedirectLocation非空时,附带Location头;
  • 304NotModified为真时,携带ETagCache-Control,必要时追加Vary: Accept-Encoding
  • 404:渲染结果 404 时直接返回;
  • 200:填充Cache-ControlVaryETagContent-Type,二进制 gzip 资源 base64 编码并标记IsBase64Encoded = true

按请求定制配置

两个入口都支持可选的每请求配置回调:

// 静态工厂 var handler = ScalarApiReferenceHandler.Create(options => options.Title = "My API"); // DI 路径:HandleAsync 的第三个参数可拿到原始请求 var response = await scalar.HandleAsync(request, context, (options, req) => { options.Title = $"My API ({req.RequestContext.DomainName})"; });

IScalarApiReference.HandleAsync的完整签名(IScalarApiReference.cs)支持Action<ScalarOptions, APIGatewayHttpApiV2ProxyRequest>? configureOptions,让你可以根据请求上下文(如 DomainName)动态调整标题、文档等配置。

8. 限制与路线图

参考 docs/limitations.md,当前版本有以下边界需要知晓:

  1. 必须自行提供函数:与 Azure Functions 集成一致(不同于 ASP.NET Core 集成中MapScalarApiReference()自动注册端点),你需要自己声明 Lambda 函数并把请求转发给IScalarApiReferenceScalarApiReferenceHandler.Create(...)返回的委托。

  2. 仅支持 API Gateway HTTP API(payload format 2.0),以下事件源暂不支持:

    • API Gateway REST API(payload format 1.0)——APIGatewayProxyRequest/APIGatewayProxyResponse
    • Application Load Balancer 目标组;
    • Lambda Function URLs。

    官方给出的原因是这些事件形状在路由/路径参数解析、请求头结构、stage 处理上差异过大,值得做专门的适配器而非尽力而为的 shim。这也是 roadmap 项;若当下就需要,可以自行调用Scalar.Shared中的底层构建块(等价于ScalarRequestProcessor的逻辑),或改用Scalar.AspNetCore配合Amazon.Lambda.AspNetCoreServer在 Lambda 中托管完整 ASP.NET Core 应用。

  3. catch-all 参数名固定为proxy(例如Path: /scalar/{proxy+}),适配器从request.PathParameters["proxy"]读取该值来区分静态资源请求与参考页、解析文档名。

  4. 自定义域名 base path:stage 自动检测读不到 base path mapping,请显式设置ScalarOptions.RoutePrefix

  5. 完整 ASP.NET Core 应用:若通过Amazon.Lambda.AspNetCoreServer/Amazon.Lambda.AspNetCoreServer.Hosting托管完整应用,直接使用Scalar.AspNetCore包的MapScalarApiReference()即可,无需本包。

9. 源码结构速览

想要进一步深入,可以从以下文件入手:

  • integrations/dotnet/aws-lambda/docs/getting-started.md:完整的安装、双入口、路由声明与配置指南;
  • integrations/dotnet/aws-lambda/docs/http-api-model.md:HTTP API 事件模型、stage 处理与 header/编码细节;
  • integrations/dotnet/aws-lambda/docs/limitations.md:限制与 roadmap;
  • integrations/dotnet/aws-lambda/src/Scalar.Aws.Lambda/ScalarApiReference.cs:核心请求处理、stage 折叠与响应构建;
  • integrations/dotnet/aws-lambda/src/Scalar.Aws.Lambda/ScalarApiReferenceHandler.cs:零 DI 入口及按访问构建选项的适配器;
  • integrations/dotnet/aws-lambda/tests/Scalar.Aws.Lambda.Tests/ScalarApiReferenceHandlerTests.cs:覆盖索引渲染、stage 自动检测、状态隔离与双入口一致性的测试;
  • integrations/dotnet/shared/src/Scalar.Shared/Rendering/ScalarRequestProcessor.cs:与 Azure Functions 共享的托管无关请求处理器;
  • integrations/dotnet/aws-lambda/playground/template.yaml:可直接部署验证的 SAM 模板。

总而言之,Scalar.Aws.Lambda让 .NET 开发者可以在不改动现有 Lambda 业务函数架构的前提下,以最少代码(甚至零 DI)挂载一套完整的、支持 stage 自动适配与 gzip 静态资源的 Scalar API Reference 页面。只要遵循{proxy+}路由、payload format 2.0 与proxy参数名的约定,即可在几分钟内完成 API 文档的云上托管。

【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询