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

时间:2019-06-03 21:56:40

标签: c# azure azure-functions

我正在使用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网络服务代码:

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:现有连接被远程主机强行关闭”

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

逐步执行代码,输入“ await client.PostAsync()”,然后逐步执行Azure Web服务代码,直到返回return语句。然后我再次走动,在1-2分钟内没有任何反应,然后引发了异常。

有人对可能发生的事情有任何想法吗?我认为这与流试图推送过多数据或某处超时有关,但是我正在做的事情似乎无法解决此问题。

2 个答案:

答案 0 :(得分:1)

我添加并删除了关于使用HttpClient.Timeout的注释,因为我认为虽然可以解决问题,但您使用的设计存在问题。您正在使用POST请求来获取资源。您确实应该使用GET请求。通常,这种方式的工作方式是您可以调用类似

GET http://localhost:7071/api/{file_name}

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

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

答案 1 :(得分:1)

由于如下所示,Azure Functions的默认超时期限受到限制,因此您会遇到问题str2,该问题是从Azure Functions下载大文件的。请参阅Functions limits

enter image description here

因此,这些小文件可以在不到超时时间的短时间内下载,但是大文件将在超时后被强制关闭。

解决方案是使用SAS令牌从Azure Function向客户端响应blob url,然后通过sas url从Azure Blob Storage直接下载blob,这是因为sas url无需额外的身份验证并且对Azure存储没有超时限制。

如果您不熟悉如何为Blob生成SAS令牌,则可以参考官方示例代码Getting Started with Shared Access Signatures (SAS)