From f2ec40a533b4b323d324935509e96274378818a4 Mon Sep 17 00:00:00 2001 From: MSuMshk <2039814060@qq.com> Date: Mon, 15 Dec 2025 13:25:04 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DCOS=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E6=8D=9F=E5=9D=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Providers/S3StorageProviderBase.cs | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/Modules/TakeoutSaaS.Module.Storage/Providers/S3StorageProviderBase.cs b/src/Modules/TakeoutSaaS.Module.Storage/Providers/S3StorageProviderBase.cs index 0745830..6251c01 100644 --- a/src/Modules/TakeoutSaaS.Module.Storage/Providers/S3StorageProviderBase.cs +++ b/src/Modules/TakeoutSaaS.Module.Storage/Providers/S3StorageProviderBase.cs @@ -60,6 +60,12 @@ public abstract class S3StorageProviderBase : IObjectStorageProvider, IDisposabl /// public virtual async Task UploadAsync(StorageUploadRequest request, CancellationToken cancellationToken = default) { + // 0. 兜底重置流位置,避免上游读取导致内容缺失 + if (request.Content.CanSeek) + { + request.Content.Position = 0; + } + // 1. 构建上传请求 var putRequest = new PutObjectRequest { @@ -67,9 +73,18 @@ public abstract class S3StorageProviderBase : IObjectStorageProvider, IDisposabl Key = request.ObjectKey, InputStream = request.Content, AutoCloseStream = false, - ContentType = request.ContentType + ContentType = request.ContentType, + DisableDefaultChecksumValidation = true, + UseChunkEncoding = false, + DisablePayloadSigning = true }; + // 1.1 显式设置 Content-Length,避免 S3 SDK 对兼容网关使用 aws-chunked 导致对象内容被写入“chunk-signature”头而损坏 + if (request.ContentLength > 0) + { + putRequest.Headers.ContentLength = request.ContentLength; + } + foreach (var kv in request.Metadata) { putRequest.Metadata[kv.Key] = kv.Value; @@ -167,17 +182,50 @@ public abstract class S3StorageProviderBase : IObjectStorageProvider, IDisposabl /// protected virtual IAmazonS3 CreateClient() { + // 1. 尽量推断鉴权 Region(腾讯云 COS 的 S3 兼容域名形如:cos.ap-beijing.myqcloud.com) + var authenticationRegion = ResolveAuthenticationRegion(ServiceUrl); + + // 2. 构建客户端配置 var config = new AmazonS3Config { ServiceURL = ServiceUrl, ForcePathStyle = ForcePathStyle, - UseHttp = !UseHttps + UseHttp = !UseHttps, + AuthenticationRegion = authenticationRegion }; + // 3. 创建客户端并返回 var credentials = new BasicAWSCredentials(AccessKey, SecretKey); return new AmazonS3Client(credentials, config); } + private static string? ResolveAuthenticationRegion(string serviceUrl) + { + // 1. 解析 URL + if (!Uri.TryCreate(serviceUrl, UriKind.Absolute, out var uri)) + { + return null; + } + + // 2. 提取 Host + var host = uri.Host; + if (string.IsNullOrWhiteSpace(host)) + { + return null; + } + + // 3. 按 COS 域名规则解析 Region + const string cosPrefix = "cos."; + const string cosSuffix = ".myqcloud.com"; + if (host.StartsWith(cosPrefix, StringComparison.OrdinalIgnoreCase) && + host.EndsWith(cosSuffix, StringComparison.OrdinalIgnoreCase)) + { + var regionPart = host.Substring(cosPrefix.Length, host.Length - cosPrefix.Length - cosSuffix.Length); + return string.IsNullOrWhiteSpace(regionPart) ? null : regionPart; + } + return null; + } + private IAmazonS3 Client => _client ??= CreateClient(); ///