C# 从Azure下载文件的Web服务引发大文件异常

C# 从Azure下载文件的Web服务引发大文件异常,c#,azure,azure-functions,C#,Azure,Azure Functions,我正在Azure中开发一个web服务框架,以及一个与Azure通信的网站。网站应该使用文件名调用Azure,Azure中的web服务应该在blob存储中找到给定的文件,并将其发送回客户端进行下载 只要返回的文件很小,我就可以让它工作(使用20mb mp4文件进行测试很好),但类似1Gb mp4的文件最终会引发异常 C#请求代码: public override async Task ProcessRequestAsync(HttpContext context) { JavaScript

我正在Azure中开发一个web服务框架,以及一个与Azure通信的网站。网站应该使用文件名调用Azure,Azure中的web服务应该在blob存储中找到给定的文件,并将其发送回客户端进行下载

只要返回的文件很小,我就可以让它工作(使用20mb mp4文件进行测试很好),但类似1Gb mp4的文件最终会引发异常

C#请求代码:

public override async Task ProcessRequestAsync(HttpContext context)
{
    JavaScriptSerializer oSearlizer = new JavaScriptSerializer();
    object o = new
    {
        sourceStorageAccountName = "accountName",
        sourceStorageAccountKey = "accountKey",
        sourceContainer = "test"
    };

    string req = oSearlizer.Serialize(o);
    HttpContent content = new StringContent(req, Encoding.UTF8, "application/json");
    HttpClient client = new HttpClient();

    HttpResponseMessage x = await client.PostAsync("http://localhost:7071/api/get_file", content);
    context.Response.Clear();
    context.Response.Buffer = false;
    context.Response.BufferOutput = false;
    context.Response.ContentType = "video/mp4";
    context.Response.AddHeader("content-disposition", "attachment;filename=test.mp4"); // Save file         
    context.Response.Charset = "";
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.BinaryWrite(await x.Content.ReadAsByteArrayAsync());
    context.Response.End();
}
Azure Web服务代码:

CloudBlobContainer sourceBlobContainer = CopyBlobHelpers.GetCloudBlobContainer(_sourceStorageAccountName, _sourceStorageAccountKey, _sourceContainer);
CloudBlockBlob blob = sourceBlobContainer.ListBlobs().First();

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
Stream stream = blob.OpenRead(null, new BlobRequestOptions() { ServerTimeout = new System.TimeSpan(2, 59, 59), MaximumExecutionTime = new System.TimeSpan(2, 59, 59) });
response.Content = new StreamContent(stream);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileNameZip;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("video/mp4");

return response;

正如我所说,这段代码对于20mb的mp4文件很好,但是对于1Gb或更大的mp4文件会抛出一个异常。我得到的异常是:“异常:SocketException:远程主机强制关闭了现有连接”

如果我从请求代码中删除“wait”并使用“.Result”,则会得到另一个异常:“exception:HttpRequestException:将内容复制到流时出错。”

在代码中,输入“wait client.PostAsync()”,我将逐步遍历Azure web服务代码,直到返回语句。然后我再次执行步骤,在1-2分钟内什么都没有发生,然后抛出异常


有人对可能发生的事情有什么想法吗?我认为这与流试图推送过多数据或某个地方超时有关,但我所做的一切似乎都无法解决问题。

我添加并删除了一条关于使用
HttpClient.Timeout
的评论,因为我认为,虽然这可能会解决问题,您使用的设计存在问题。您正在使用POST请求获取资源。您确实应该使用GET请求。通常情况下,这样做的方式是,您可以调用

GEThttp://localhost:7071/api/{文件名}

其中,
{file_name}
是要下载的文件的名称。服务通常会知道有关存储帐户的信息,因此您不需要当前拥有的请求主体。您可能希望该服务不知道从哪个存储帐户下载,但我认为这不太可能


我还觉得有必要注意,如果您要继续通过网络发送存储帐户信息,您需要使用HTTPS而不是HTTP,因为现在,您正在以明文形式发送存储帐户密钥。

因为Azure函数有一个默认超时时间限制,如下所示,因此,您将遇到问题
异常:SocketException:从Azure函数下载大型文件时,远程主机强制关闭了现有连接。请参阅

因此,这些小文件可以在小于超时持续时间的短时间内下载,但大文件将在超时后强制关闭

解决方案是使用SAS令牌将blob url从Azure函数响应到客户端,然后通过SAS url从Azure blob存储直接下载blob,因为SAS url没有额外的身份验证,Azure存储也没有超时限制


如果您不熟悉如何为blob生成SAS令牌,可以参考官方示例代码

,虽然这些都是优点,但它们不一定能解决我遇到的问题。即使在添加HttpClient.Timeout 3小时后,连接仍会在约1分钟后关闭。