首页 > 解决方案 > 尝试将 HttpClient.GetStreamAsync 直接用于 adls FileClient.UploadAsync

问题描述

我有一个 Azure 函数,它将通过 HttpClient 调用外部 API。外部 API 返回 JSON 响应。我想将响应直接保存到 ADLS 文件。

我的简单代码是:

public async Task UploadFileBulk(Stream contentToUpload)
{
   await this._theClient.FileClient.UploadAsync(contentToUpload);            
}

this._theClient 是围绕各种 Azure Data Lake 类(如 DataLakeServiceClient、DataLakeFileSystemClient、DataLakeDirectoryClient、DataLakeFileClient)的简单包装类。

我很高兴这个包装器调用按我的预期工作,我启动一个,设置服务、文件系统、目录,然后创建一个文件名。我已经使用这个包装类来创建目录等,所以它可以按我的预期工作。

我将上述方法调用如下:

await dlw.UploadFileBulk(await this._httpClient.GetStreamAsync("<endpoint>"));  

我看到在 Lake 目录中创建了我想要的文件,但是如果我然后使用 Sorage Explorer 下载文件,然后尝试以 VS Code 的形式打开它,它不是可识别的格式(我可以“强制”代码打开它,但对我来说它看起来像二进制格式)。

如果我用 fiddler 嗅探流量,我可以看到来自外部 API 的内容是 JSON,内容类型是 application/json,body 在 fiddler 中显示为 JSON。

如果我查看对 ADLS 端点的调用,我可以看到一个 PUT 调用,然后是两个 PATCH 调用。

第一个 PATCH 调用看起来像是发送内容的调用,它有一个 application/octet-stream 的内容标头,请求正文是“二进制内容”。

我正在使用 HttpClient.GetStreamAsync 因为我不希望我的函数必须将整个 API 有效负载加载到内存中(一些外部 API 端点返回超过 100mb 的非常大的文件)。我想我可以“将来自外部 API 的响应直接流式传输到 ADLS”。

有没有办法改变 ADLS FileClient.UploadAsync(Stream stream) 方法的工作方式,以便我可以告诉它将文件作为 JSON 文件上传,内容类型为 application/json?

编辑:事实证明,外部 API 正在发送回压缩内容,因此,一旦我将以下额外的 AutomaticDecompression 代码添加到我的函数启动中,我就会按预期将文件上传到 ADLS。

        public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient("default", client =>
        {
            client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");

        }).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        });
    }

@Gaurav Mantri 给了我一些关于“从输出到输入的流”模式是否真的正确的指示,我将进一步研究。

标签: azureazure-functionsazure-storagedotnet-httpclientazure-data-lake-gen2

解决方案


关于这个问题,请参考以下代码

var uploadOptions = new DataLakeFileUploadOptions();
uploadOptions.HttpHeaders = new PathHttpHeaders();
uploadOptions.HttpHeaders.ContentType ="application/json";
await fileClient.UploadAsync(stream, uploadOptions);

推荐阅读