简体   繁体   English

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

[英]Web Service to download files from Azure throws exception for large files

I'm working on a web service framework in Azure, as well as a website to communicate with Azure. 我正在使用Azure中的Web服务框架以及与Azure进行通信的网站。 The website should make a call to Azure with a filename, and the web service in Azure should find the given file in blob storage and send it back to the client for downloading. 网站应使用文件名调用Azure,Azure中的Web服务应在blob存储中找到给定的文件,并将其发送回客户端进行下载。

I can get this to work as long as the file being returned is small (testing with a 20mb mp4 file works fine), but something like a 1Gb mp4 file ends up throwing an exception. 只要返回的文件很小(使用20mb mp4文件进行测试就可以了),我就可以使它正常工作,但是像1Gb mp4文件这样的东西最终会引发异常。

C# request code: 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 webservice code: 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;

Like I said, this code works fine for an mp4 file of 20mb, but throws an exception for a 1Gb mp4 file or larger. 就像我说的那样,此代码适用于20mb的mp4文件,但是对于1Gb mp4或更大的文件会引发异常。 The exception I get is: "Exception: SocketException: An existing connection was forcibly closed by the remote host" 我得到的异常是:“异常:SocketException:现有连接被远程主机强行关闭”

If I remove the "await"'s from the request code and use ".Result" instead, I get a different exception: "Exception: HttpRequestException: Error while copying content to a stream." 如果我从请求代码中删除“ await”并使用“ .Result”,则会收到另一个异常:“异常:HttpRequestException:将内容复制到流时出错。”

Stepping through the code, it enters "await client.PostAsync()", I step through the Azure web service code until the return statement. 逐步执行代码,然后输入“ await client.PostAsync()”,然后逐步执行Azure Web服务代码,直到返回return语句。 Then I step again and nothing happens for 1-2min, and then the exception is thrown. 然后我再次走动,并且在1-2分钟内什么都没有发生,然后引发异常。

Does anyone have any ideas about what might be going on? 是否有人对可能发生的事情有任何想法? I'm thinking it has something to do with the stream trying to push through too much data or a time-out somewhere, but nothing I'm doing seems to be solving the issue. 我在想它与试图推送过多数据或某处超时的流有关,但是我正在做的事情似乎无法解决此问题。

I added and then deleted a comment about using HttpClient.Timeout because I think that, while that might fix the problem, there is an issue with the design you are using. 我添加并删除了关于使用HttpClient.Timeout的注释,因为我认为虽然可以解决问题,但您使用的设计存在问题。 You are using a POST request to get a resource. 您正在使用POST请求来获取资源。 You really should be using a GET request. 您确实应该使用GET请求。 Normally, the way this works is that you would call something like 通常,这种方法的工作方式是

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

where {file_name} is the name of the file that you want to download. 其中{file_name}是您要下载的文件的名称。 The service would generally know the information about the storage account, and so you wouldn't need the request body that you currently have. 该服务通常会知道有关存储帐户的信息,因此您不需要当前拥有的请求正文。 It is possible that you want the service to be agnostic to which storage account to download from, but I think that's pretty unlikely. 您可能希望服务与从哪个存储帐户下载无关,但我认为这不太可能。

I also feel like it's necessary to note that if you are going to continue sending the storage account information over the wire, you need to be using HTTPS instead of HTTP, because as it stands now, you are sending the storage account key in plaintext. 我还觉得有必要注意一下,如果您要继续通过网络发送存储帐户信息,则需要使用HTTPS而不是HTTP,因为从现在开始,您将以明文形式发送存储帐户密钥。

Due to there is a limit of default time out duration for Azure Functions, as below, so you will get the issue Exception: SocketException: An existing connection was forcibly closed by the remote host for downloading a large file from Azure Functions. 由于如下所示,Azure Functions的默认超时时间受到限制,因此您将遇到以下Exception: SocketException: An existing connection was forcibly closed by the remote host以便从Azure Functions下载大文件。 Please refer to Functions limits . 请参阅功能限制

在此处输入图片说明

Therefore, these small files can be downloaded in short time less than timeout duration, but the large file will be forcibly closed after timeout. 因此,可以在少于超时时间的短时间内下载这些小文件,但是在超时后将强制关闭大文件。

The solution is to response the blob url with SAS token from Azure Function to client, and then directly download the blob via sas url from Azure Blob Storage, because of the sas url without extra authentication and no timeout limits on Azure Storage. 解决方案是使用SAS令牌从Azure Function向客户端响应blob URL,然后再通过SAS URL从Azure Blob Storage直接下载blob,这是因为SAS URL没有额外的身份验证并且对Azure存储没有超时限制。

If you are not familiar with how to generate SAS token for a blob, you can refer to the offical sample code Getting Started with Shared Access Signatures (SAS) 如果您不熟悉如何为Blob生成SAS令牌,则可以参考官方示例代码“ 共享访问签名入门(SAS)”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM