AWS SDK for .NET (v3) 实战指南:用 S3 Conditional Requests 场景示例掌握 ETag 与时间条件请求
示例工程教程后端【免费下载链接】aws-doc-sdk-examplesWelcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.项目地址https://gitcode.com/gh_mirrors/aw/aws-doc-sdk-examples点击查看免费下载本文围绕 aws-doc-sdk-examples 仓库中dotnetv3目录下的 S3 条件请求功能场景Feature Scenario讲解如何在 AWS SDK for .NET 3.x 中为 S3 的读、复制、写操作附加 HTTP 条件头If-Match、If-None-Match、If-Modified-Since、If-Unmodified-Since。读完本文你将理解四类条件头的语义与预期成败结果、各条件头在GetObjectRequest、CopyObjectRequest、PutObjectRequest上对应的 SDK 属性以及条件失败时PreconditionFailed与NotModified错误码的捕获处理方式并能独立运行和自动化验证该交互场景。一、S3 条件请求的核心概念Amazon S3 的 Conditional Requests 允许为 S3 的读GET、复制Copy和写PUT请求附加前置条件preconditions使操作基于对象的 ETagEntity Tag或最后修改时间Last-Modified成功或失败。这是实现乐观并发控制的基础手段典型用途包括防止覆盖写入前用If-None-Match: *断言目标 Key 尚不存在避免误覆盖已有对象基于版本校验读取用If-Match校验对象 ETag 是否与上次看到的一致检测到对象已被他人修改时放弃操作基于时间窗口读取用If-Modified-Since/If-Unmodified-Since限定对象的最后修改时间条件复制复制对象前对源对象附加同样的条件防止复制到一个已变更的旧版本。仓库中该场景的说明文档为 S3 条件请求场景 README其中将整个交互演示划分为三个阶段Setup准备创建测试桶bucket和测试对象Conditional Reads and Writes条件读写列出对象、执行带条件的读/写/复制操作并观察请求结果Clean清理删除所有对象和桶。⚠️ 运行该代码可能产生 AWS 费用测试同样可能产生费用建议按最小权限原则授予代码执行所需的最少 IAM 权限并注意该代码未在所有 AWS Region 都经过测试。场景本身不需要额外资源所需的桶和对象均由 Setup 阶段自动创建。需要说明的是该场景位于dotnetv3AWS SDK for .NET 3.x目录下配套通用前提.NET SDK、AWS 凭据配置方式等可参阅 dotnetv3 根 README。二、工程结构与运行方式场景位于 S3ConditionalRequestsScenario 目录采用标准 .NET 解决方案布局包含三个工程文件文件作用S3ConditionalRequestsScenario.sln解决方案文件dotnet run的入口目录S3ConditionalRequestsScenario.csproj控制台主工程net8.0S3ConditionalRequestsScenarioTests.csxUnit 集成测试用于非交互模式验证全流程主工程 S3ConditionalRequestsScenario.csproj 中的关键依赖为PackageReference IncludeAWSSDK.Extensions.NETCore.Setup Version3.7.301 / PackageReference IncludeAWSSDK.S3 Version3.7.410.4 /其中AWSSDK.Extensions.NETCore.Setup提供AddAWSServiceIAmazonS3()扩展方法用于把 S3 客户端注册进 DI 容器。工程还通过Content Includesettings.jsonCopyToOutputDirectoryPreserveNewest/CopyToOutputDirectory/Content把配置文件复制到输出目录运行期由ConfigurationBuilder加载。配置文件 settings.json默认配置 settings.json 只有一个键{ resourcePrefix: dotnet-s3-conditional-requests-example }resourcePrefix决定全部资源命名源桶名为{prefix}-source、目标桶名为{prefix}-dest、示例对象 Key 为{prefix}-sample-object.txt见 ConfigurationSetup 方法。若未提供该键回退默认值为dotnet-example。程序同时支持可选的settings.local.json覆盖配置以optional: true方式加载便于在不改动默认配置的情况下本地调整前缀。运行命令编译完成后进入包含.sln文件的目录执行dotnet run或者直接在 IDE 中运行。程序启动后进入交互模式依次完成资源准备、菜单式条件请求演示、资源清理。三、程序入口与依赖注入入口类为 S3ConditionalRequestsScenario。Main方法首先构建一个默认的 Host并注册 AWS S3 服务using var host Host.CreateDefaultBuilder(args) .ConfigureLogging(logging logging.AddFilter(System, LogLevel.Debug) .AddFilterDebugLoggerProvider(Microsoft, LogLevel.Information) .AddFilterConsoleLoggerProvider(Microsoft, LogLevel.Trace)) .ConfigureServices((_, services) services.AddAWSServiceIAmazonS3() .AddTransientS3ActionsWrapper()) .Build();可以看到该场景采用泛型 Host 的依赖注入方式IAmazonS3客户端由AWSSDK.Extensions.NETCore.Setup包创建并注册业务包装类S3ActionsWrapper以AddTransient方式注入后续所有 S3 调用都收敛到这一个类中。类中还有一个_interactive静态开关默认为true交互模式下菜单等待用户输入非交互模式下自动化测试会将其置为false所有输入直接采用默认值这正是集成测试能够全自动跑通的原因。四、Setup 阶段条件写入首次登场Setup方法源码完成三件事创建源桶{prefix}-source与目标桶{prefix}-dest以条件写入方式向源桶上传文本Test file content.对象 Key 为{prefix}-sample-object.txt返回上传结果的 ETag供后续条件读/条件复制作为条件值使用。这里值得注意的是连 Setup 阶段的上传本身就是一次条件写入调用PutObjectConditional(objectKey, sourceBucket, Test file content.)——因为目标 Key 尚不存在条件满足写入成功并返回 ETag。桶创建方法CreateBucketWithName还实现了一个实用细节PutBucket成功后桶并非立即可用代码最多以 5 秒间隔轮询 5 次AmazonS3Util.DoesS3BucketExistV2Async确认桶就绪源码。若桶已存在则捕获BucketAlreadyExistsException并视为成功使场景具备重跑幂等性。五、条件读取GetObjectRequest 的条件属性映射核心业务封装在 S3ActionsWrapper.cs 中。四类条件由枚举 S3ConditionType 表示public enum S3ConditionType { IfMatch, IfNoneMatch, IfModifiedSince, IfUnmodifiedSince }GetObjectConditional方法源码将枚举值映射到GetObjectRequest的对应属性条件头SDK 属性语义If-MatchGetObjectRequest.EtagToMatch对象 ETag 与给定值相同才返回对象If-None-MatchGetObjectRequest.EtagToNotMatch对象 ETag 与给定值不同才返回对象If-Modified-SinceGetObjectRequest.ModifiedSinceDateUtc对象在给定 UTC 时间之后修改过才返回If-None-Match/If-Unmodified-Since同理GetObjectRequest.UnmodifiedSinceDateUtc对象在给定 UTC 时间之前未修改才返回映射逻辑通过switch完成switch (conditionType) { case S3ConditionType.IfMatch: getObjectRequest.EtagToMatch etagConditionalValue; break; case S3ConditionType.IfNoneMatch: getObjectRequest.EtagToNotMatch etagConditionalValue; break; case S3ConditionType.IfModifiedSince: getObjectRequest.ModifiedSinceDateUtc conditionDateValue.GetValueOrDefault(); break; case S3ConditionType.IfUnmodifiedSince: getObjectRequest.UnmodifiedSinceDateUtc conditionDateValue.GetValueOrDefault(); break; default: throw new ArgumentOutOfRangeException(nameof(conditionType), conditionType, null); }成功时读取并打印对象前 20 个字节用于展示。失败处理是理解条件请求语义的关键AmazonS3Exception被捕获后按ErrorCode区分——PreconditionFailed条件明确不满足例如If-None-Match命中的 ETag 正是当前对象 ETag返回falseNotModified时间条件不满足例如If-Unmodified-Since早于对象实际修改时间返回false其他错误码视为异常重新抛出。六、条件复制CopyObjectRequest 的条件属性映射CopyObjectConditional源码演示了源对象条件在跨桶复制中的作用。它构造CopyObjectRequestSourceBucket/SourceKey/DestinationBucket/DestinationKey再用同一套S3ConditionType枚举映射到复制请求的源条件属性条件头SDK 属性If-MatchCopyObjectRequest.ETagToMatchIf-None-MatchCopyObjectRequest.ETagToNotMatchIf-Modified-SinceCopyObjectRequest.ModifiedSinceDateUtcIf-Unmodified-SinceCopyObjectRequest.UnmodifiedSinceDateUtc交互菜单中条件复制会先询问目标对象 Key默认sampleObjectKey然后把源桶中的示例对象复制到目标桶。从源码结构看复制路径的错误处理与读取路径几乎对称但有一个值得注意的差异复制失败时的未修改错误码字符串是304HTTP 304 Not Modified 的数字形式而读取路径使用的是NotModified——两种写法都对应条件复制/读取未通过时间条件的场景捕获时以代码中的实际字符串为准。七、条件写入If-None-Match * 防止覆盖条件写入是本场景最贴近生产实践的用法。PutObjectConditional源码非常简洁var putObjectRequest new PutObjectRequest { BucketName bucket, Key objectKey, ContentBody content, IfNoneMatch * };IfNoneMatch *的语义是仅当目标 Key 不存在时才允许写入。一旦该 Key 已存在任何版本S3 返回PreconditionFailed写入被拒绝——这就是create if not exists原子创建模式的 SDK 实现。方法成功时返回 ETag空字符串表示失败调用方据此判断是否发生了重复写入。交互菜单中的第 4 项Perform a conditional write正是让用户输入一个对象 Key 来体验这一点输入一个新 Key 时写入成功如果输入已存在的 Key例如 Setup 阶段创建的{prefix}-sample-object.txt写入会因PreconditionFailed失败日志输出 Conditional write failed: Precondition failed。八、四个条件选项的预期结果交互菜单DisplayDemoChoices源码提供了 5 个主菜单项列出桶内容、条件读、条件复制、条件写、清理退出其中条件读/条件复制共享同一组 4 个条件选项。以 Setup 阶段刚创建的对象为基准各条件的预期结果如下条件选项条件值预期结果原因If-Match对象当前 ETag成功ETag 匹配条件满足If-None-Match对象当前 ETag失败PreconditionFailed要求 ETag 不同实际相同If-Modified-Since昨天DateTime.UtcNow.AddDays(-1)成功对象是现在刚创建的晚于昨天If-Unmodified-Since昨天失败Not Modified对象在昨天之后被修改过条件不成立其中日期类条件统一使用yesterdayDate DateTime.UtcNow.AddDays(-1)ETag 类条件使用 Setup 阶段返回的_sampleObjectEtag。选择If-Match/If-None-Match时调用GetObjectConditional(objectKey, sourceBucket, conditionTypes[i], null, _sampleObjectEtag)选择时间类条件时传入yesterdayDate。非交互模式下每轮循环只执行默认选项一次后跳出因此主流程与集成测试都以逐一切换默认值的方式遍历全部功能。九、自动化验证非交互集成测试场景自带的测试项目 S3ConditionalRequestsScenarioTests 展示了如何用同一套代码做全链路集成验证。测试构造器中从 testsettings.json 读取测试专用前缀dotnet-s3-conditional-requests-example-test与演示用的默认前缀隔离避免资源互相踩踏并支持可选的testsettings.local.json直接new S3ActionsWrapper(new AmazonS3Client(), ...)并回写场景类的静态字段_s3ActionsWrapper/_configuration。核心测试方法TestScenario标注[Trait(Category, Integration)]的逻辑S3ConditionalRequestsScenario._interactive false; // 关闭交互 S3ConditionalRequestsScenario.ConfigurationSetup(); var sampleObjectEtag await S3ConditionalRequestsScenario.Setup(sourceName, destName, objKey); // 依次以默认选项 1~4 跑完整菜单覆盖条件读、条件复制、条件写、清理 await S3ConditionalRequestsScenario.DisplayDemoChoices(sourceName, destName, objKey, sampleObjectEtag, 1); await S3ConditionalRequestsScenario.DisplayDemoChoices(sourceName, destName, objKey, sampleObjectEtag, 2); await S3ConditionalRequestsScenario.DisplayDemoChoices(sourceName, destName, objKey, sampleObjectEtag, 3); await S3ConditionalRequestsScenario.DisplayDemoChoices(sourceName, destName, objKey, sampleObjectEtag, 4); await S3ConditionalRequestsScenario.Cleanup(false); Assert.NotNull(sampleObjectEtag);注意断言只要求全程无异常抛出且 ETag 非空条件失败在本场景中被视为正常业务分支GetObjectConditional等返回false而不是抛异常这正是该场景演示设计意图——条件请求的价值恰恰在于让失败成为可预期的结果。按照 dotnetv3 根 README 的说明可在测试目录下用dotnet test --filter CategoryIntegration运行集成测试会产生 AWS 费用。十、Cleanup 阶段与资源治理清理逻辑分为两层CleanupScenario/Cleanup源码交互模式下询问用户是否清理所有文件和桶 (y/n)回答n时会提示保留资源可能带来非预期费用CleanUpBucketByName源码先ListObjectsV2列出全部对象逐一DeleteObject再DeleteBucket删除空桶并容忍桶本就不存在的情况NoSuchBucket时跳过。Main的try/catch保证即使演示中途抛出异常也会调用CleanupScenario兜底清理两个桶避免遗留资源计费。小结该场景示例以约 700 行可运行的 .NET 8 代码完整覆盖了 S3 条件请求在读取、复制、写入三条路径上的 SDK 用法读与复制路径GetObjectRequest/CopyObjectRequest上的EtagToMatch、EtagToNotMatch、ModifiedSinceDateUtc、UnmodifiedSinceDateUtc四属性以及PreconditionFailed/NotModified复制路径为304两种条件失败错误码的区分捕获写路径PutObjectRequest.IfNoneMatch *实现Key 不存在才写入的原子创建语义工程化实践resourcePrefix驱动的资源命名、settings.local.json可选覆盖、交互/非交互双模式、基于默认选项轮转的集成测试构成一套可直接复制到自身项目中的场景示例模板。如需进一步扩展可以在此基础上为GetObjectConditional增加Range条件组合、将条件写入应用于版本化桶场景或把PreconditionFailed升级为带重试策略的并发冲突处理——这些都属于在同一组 SDK 属性上的自然延伸。赞分享示例工程教程后端【免费下载链接】aws-doc-sdk-examplesWelcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.项目地址https://gitcode.com/gh_mirrors/aw/aws-doc-sdk-examples点击查看免费下载相关推荐使用 AWS SDK for .NET 开发 AWS Lambda 代码示例入门、基础操作与实战场景使用 AWS SDK for .NET 开发 AWS Lambda 代码示例入门、基础操作与实战场景 导读 本文基于 dotnetv3/Lambda/READ示例工程教程后端SWR 条件数据请求Conditional Fetching与依赖请求实战指南SWR 条件数据请求Conditional Fetching与依赖请求实战指南 导读 本指南基于 nextra 仓库 https://link.gitcod前端文档/教程AWS SDK for JavaScript v3 中的 Amazon S3 代码示例解析AWS SDK for JavaScript v3 中的 Amazon S3 代码示例解析 概述 Amazon Simple Storage Service A示例工程教程后端上一篇TranslucentTB多显示器支持跨屏幕任务栏外观统一配置方案下一篇AntiMicroX终极指南游戏手柄映射神器的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考