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();
///