如何在不使用 SDK 的情况下使用 .NET HttpClient 上传到 Amazon S3

Posted

技术标签:

【中文标题】如何在不使用 SDK 的情况下使用 .NET HttpClient 上传到 Amazon S3【英文标题】:How do I upload to Amazon S3 using .NET HttpClient WITHOUT using their SDK 【发布时间】:2015-04-30 17:42:49 【问题描述】:

如何仅使用 .NET 的 HttpClient(或 WebClient)将文件上传到 Amazon S3 上的存储桶?必须使用“PUT”来完成。

我可以使用亚马逊的 AWS 开发工具包进行上传,但我想知道如何在没有它的情况下进行上传。我看了他们的文档好几个小时了,还是没明白。

任何帮助将不胜感激。

我使用他们的 SDK 的代码是:

public static void TestPutObjectAsync() 
        AmazonS3Client client = new AmazonS3Client();
        client.AfterResponseEvent += new ResponseEventHandler(callback);

        PutObjectRequest request = new PutObjectRequest 
            BucketName = BUCKET_NAME,
            Key = "Item1",
            FilePath = FILE_PATH,
        ;

        client.PutObjectAsync(request);


public static event EventHandler UploadComplete;

public static void callback(object sender, ResponseEventArgs e) 

        if (UploadComplete != null) 
            UploadComplete(sender, e);
        

【问题讨论】:

您有什么更好的方法可以在不使用 .net sdk 的情况下将文件上传到 s3 吗? 【参考方案1】:

我在尝试在 Xamarin .net 核心跨平台客户端中部署文件上传时遇到了这个问题,其中预签名的帖子是使用 boto3 在服务器端生成的。

要求是不要使用 SDK 客户端,因为虽然这个问题是关于 AWS S3,但许多其他服务(Wasabi 和 Digital Ocean 仅举几例)使用相同的 API 和 SDK 客户端的配置不同的服务可能难以管理——服务器应该处理为各种服务端点生成预签名的 POST,而客户端不应该镜像该端点。这样,我们的服务器可以轻松更改端点,而客户端不需要更新。

1:为预签帖创建支持模型。这源于https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3.html#generating-presigned-posts

public class PresignedPost

    public string url  get; set; 
    public Fields fields  get; set; 

public class Fields

    public string AWSAccessKeyId  get; set; 
    public string acl  get; set; 
    public string key  get; set; 
    public string policy  get; set; 
    public string signature  get; set; 

2:加载文件。在我们的例子中,我们通过

读入内存
string data = File.ReadAllText(filepath)

是的,这可能会导致内存中的大文件出现问题,但目前我们的要求中并未解决此限制。

3:使用 System.Net.Http 中的 HttpClient 创建 Upload 方法

public static async Task<bool> Upload(PresignedPost presignedPost, string data)
            
    using (HttpClient client = new HttpClient())
    
        try
        
            MultipartFormDataContent formData = new MultipartFormDataContent
            
                 new StringContent(presignedPost.fields.acl), "acl" ,
                 new StringContent(presignedPost.fields.AWSAccessKeyId), "AWSAccessKeyId" ,
                 new StringContent(presignedPost.fields.key), "key" ,
                 new StringContent(presignedPost.fields.policy), "policy" ,
                 new StringContent(presignedPost.fields.signature), "signature" ,
                 new StringContent(data), "file" ,
            ;
            var response = await client.PostAsync(presignedPost.url, formData);
            //if response is 204 no content it's successful
            if (response.StatusCode == HttpStatusCode.NoContent)
            
                return true;
            
        
        catch (Exception ex)
        
            //do something with exception
        
    
    return false;

评论:

1:也可以将文件加载为字节数组,然后使用 formData 中的内存流。这在上传较大的文件时可能会有所帮助,但是,我们的堆栈首先加密文件并返回一个字符串,因此我们在此实现中没有选择该方法。参考:C# HttpClient 4.5 multipart/form-data upload 或者简单地使用字节数组而不是字符串 ref:send byte array by HTTP POST in store app

2:您可能会注意到,我们假设 204 响应代码表示上传成功。虽然这显然很危险,但我们找不到任何关于为什么会发生这种情况的文档 - 也许这与 AWS S3 Object DELETE 也返回 204 的原因相同。如果您担心这一点,您可以添加一个 API 调用来检查如果文件存在。

3:是的,有关于使用“使用”处理 HttpClients 的争论,您可以根据您的用例参考:https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

4:是否返回布尔值,请根据自己的实践和要求进行选择。

最后,我希望这可以帮助任何面临此问题的人,因为 AWS S3 文档中没有现成的示例。

【讨论】:

【参考方案2】:

不确定您为什么不想使用 SDK(这就是它的用途),但即使您不想使用整个 AWSSDK,您仍然可以使用其中的一部分 - 或者至少看看如何他们在幕后做这件事。

这里全部开源:

https://github.com/aws/aws-sdk-net/tree/master/AWSSDK_DotNet45/Amazon.S3

最终,您正在寻找的答案就在其中 - 但它可能比将其取出来的工作更多。

【讨论】:

啊,没想到要看看,谢谢!我将浏览它,看看它是否值得。我的程序中有另一个 API 处理程序发出 HTTP 请求,我计划使用单独的 API 处理程序来组装请求,然后使用单个 HttpHandler 类来实际发出请求。这就是我对使用原生 .NET 工具感兴趣的原因。 链接现在是 404,我假设这是新的 URL:github.com/aws/aws-sdk-net 不想使用 Amazon SDK 的一个很好的理由是通过下载几兆字节大的 .DLL(例如 AWSDK.S3 超过 2MB)来避免使原本纤细的项目变得臃肿。例如客户端 Blazor 站点。

以上是关于如何在不使用 SDK 的情况下使用 .NET HttpClient 上传到 Amazon S3的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 Android SDK 的 playUri 的情况下获取歌曲元数据?

如何在不刷新页面的情况下使用 JS SDK 检测从 fb 注销

如何在不使用 SDK 的情况下将文件从 Android 上传到 Amazon S3

如何在不暴露源代码的情况下将 SDK 分发为 AAR 文件?

如何在不使用 Facebook 登录/注销按钮的情况下以编程方式从 Facebook SDK 3.0 注销?

如何在不创建或附加 Azure Java SDK 的情况下获取 AppendBlobItem