You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 5下AWSSDK.S3上传S3文件损坏问题求助

.NET 5环境下AWSSDK.S3上传S3文件损坏问题

上传至S3后的文件出现损坏,开头被附加了类似14000;chunk-signature=xxx的内容,本地保存的文件则完全正常。上传后的文件十六进制预览如下:

00000000  31 34 30 30 30 3B 63 68  75 6E 6B 2D 73 69 67 6E  14000;chunk-sign
00000010  61 74 75 72 65 3D 30 38  65 37 65 34 31 61 35 65  ature=08e7e41a5e
00000020  33 32 30 62 38 37 33 39  34 66 36 35 37 33 34 35  320b87394f657345
00000030  61 32 31 62 66 30 33 32  37 33 33 31 35 62 64 36  a21bf03273315bd6
00000040  64 31 32 30 35 38 37 63  61 62 65 30 36 39 34 61  d120587cabe0694a
00000050  38 66 33 30 30 63 0D 0A  89 50 4E 47 0D 0A 1A 0A  8f300c...PNG....

以下是代码实现:

Startup.cs

var awsOptions = Configuration.GetSection("AWSSettings");
var credentials = new BasicAWSCredentials(awsOptions["AccessKey"], awsOptions["SecretKey"]);

AWSConfigsS3.UseSignatureVersion4 = true;

var awsConfig = new AmazonS3Config
            {
                ServiceURL = awsOptions["ServiceURL"],
                UseHttp = false,
                ForcePathStyle = true,
                SignatureVersion = "4"
            };

awsConfig.GetType().GetProperty("DisablePayloadSigning")?.SetValue(awsConfig, true);

services.AddSingleton<IAmazonS3>(sp => new AmazonS3Client(credentials, awsConfig));

Controller

[AllowAnonymous, HttpPost("upload")]
public async Task<ActionResult<CustomResponse<UploadFileResponse>>> Upload([FromForm] TestFileRequest request, CancellationToken cancellationToken)
{
    try
    {
        var response = await _s3Service.UploadFileAsync(request.File, FileDirectory.AWSBucket, FileDirectory.AWSDirectory, cancellationToken);
        return ResponseHandler.CreateResponse(response.StatusCode, response.Data, response.Message);
    }
    catch (Exception ex)
    {
        return ResponseHandler.CreateErrorResponse<UploadFileResponse>(ex);
    }
}

Service

public async Task<CustomResponse<UploadFileResponse>> UploadFileAsync(
            IFormFile file,
            string bucketName = AWSBucket,
            string directory = AWSBucketDirectoty,
            CancellationToken cancellationToken = default)
{
    try
    {
        if (file == null || file.Length == 0)
            return new CustomResponse<UploadFileResponse>(400, null, "File is empty or not selected.");

        var id = Guid.NewGuid();
        var fileExtension = Path.GetExtension(file.FileName);
        var newFileName = $"{id}{fileExtension}";
        var key = $"{directory}/{newFileName}";

        using var memoryStream = new MemoryStream();
        await file.CopyToAsync(memoryStream, cancellationToken);

        memoryStream.Position = 0; // Reset stream position

        // Debug: Save file locally to verify it's not corrupt
        await File.WriteAllBytesAsync("debug_image.png", memoryStream.ToArray(), cancellationToken);

        // Use TransferUtility to Upload
        using var transferUtility = new TransferUtility(_s3Client);
        await transferUtility.UploadAsync(new TransferUtilityUploadRequest
                {
                    BucketName = bucketName,
                    Key = key,
                    InputStream = memoryStream,
                    ContentType = file.ContentType ?? "application/octet-stream",
                    CannedACL = S3CannedACL.Private, // Adjust permissions if needed
                    StorageClass = S3StorageClass.Standard // Optional: Set storage class
                }, cancellationToken);

        var preSignedUrl = GetPreSignedURL(key, bucketName);

        var uploadFileResponse = new UploadFileResponse
                {
                    Id = id,
                    FileName = newFileName,
                    Extension = fileExtension,
                    ContentType = file.ContentType,
                    PreSignedUrl = preSignedUrl
                };

        return new CustomResponse<UploadFileResponse>(200, uploadFileResponse);
    }
    catch (Exception ex)
    {
        return new CustomResponse<UploadFileResponse>(500, null, $"Unexpected error: {ex.Message}");
    }
}

问题原因

手动设置DisablePayloadSigning = true的同时启用了Signature Version 4,导致请求被错误添加分块签名头部,这些签名内容最终被写入文件 payload,造成文件损坏。DisablePayloadSigning属于SDK内部API,不应手动修改。

解决办法

  1. 移除DisablePayloadSigning的手动设置
    删除这行代码:

    awsConfig.GetType().GetProperty("DisablePayloadSigning")?.SetValue(awsConfig, true);
    

    AWS SDK会根据签名版本自动处理payload签名逻辑,无需手动干预。

  2. 重置流位置(修复调试代码的副作用)
    调用File.WriteAllBytesAsync后,流的位置会移到末尾,需要再次重置后再上传:

    await File.WriteAllBytesAsync("debug_image.png", memoryStream.ToArray(), cancellationToken);
    memoryStream.Position = 0; // 再次重置流位置
    
  3. 改用PutObjectAsync直接上传(可选)
    如果TransferUtility仍有问题,可尝试直接使用PutObjectAsync上传:

    var putRequest = new PutObjectRequest
    {
        BucketName = bucketName,
        Key = key,
        InputStream = memoryStream,
        ContentType = file.ContentType ?? "application/octet-stream",
        CannedACL = S3CannedACL.Private
    };
    await _s3Client.PutObjectAsync(putRequest, cancellationToken);
    

内容的提问来源于stack exchange,提问作者Angelica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:29:55