Веб-служба для загрузки файлов из Azure выдает исключение для больших файлов - PullRequest
1 голос
/ 04 июня 2019

Я работаю над платформой веб-службы в Azure, а также над веб-сайтом для связи с Azure.Веб-сайт должен позвонить в Azure с именем файла, а веб-служба в Azure должна найти указанный файл в хранилище больших двоичных объектов и отправить его клиенту для загрузки.

Я могу заставить это работать до тех пор, покатак как возвращаемый файл небольшой (тестирование с mp4-файлом объемом 20 Мб работает нормально), но что-то вроде 14-гигабайтного 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;

Как я уже сказал, этот код отлично работает для файла mp4 размером 20 Мб, но выдает исключение для файла mp4 объемом 1 ГБ или более.Исключение, которое я получаю: «Исключение: SocketException: существующее соединение было принудительно закрыто удаленным хостом»

Если я удаляю «await» из кода запроса и использую вместо этого «.Result», яполучите другое исключение: «Исключение: HttpRequestException: ошибка при копировании содержимого в поток».

При переходе по коду он вводит «await client.PostAsync ()», я выполняю код веб-службы Azure, покаответное заявление.Затем я делаю шаг снова, и ничего не происходит в течение 1-2 минут, а затем выдается исключение.

У кого-нибудь есть идеи о том, что может происходить?Я думаю, что это как-то связано с тем, что поток пытается протолкнуть слишком много данных или тайм-аут где-то, но, похоже, ничто из того, что я делаю, не решает проблему.

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Из-за ограничения по умолчанию времени ожидания для функций Azure, как показано ниже, вы получите проблему Exception: SocketException: An existing connection was forcibly closed by the remote host для загрузки большого файла из функций Azure. Пожалуйста, обратитесь к Ограничения функций .

enter image description here

Таким образом, эти небольшие файлы могут быть загружены за короткое время, меньшее времени ожидания, но большой файл будет принудительно закрыт после истечения времени ожидания.

Решение состоит в том, чтобы отправить URL-адрес большого двоичного объекта с токеном SAS из функции Azure клиенту, а затем напрямую загрузить большой двоичный объект по URL-адресу sas из хранилища BLOB-объектов Azure из-за URL-адреса sas без дополнительной проверки подлинности и без ограничений по времени ожидания в хранилище Azure.

Если вы не знакомы с тем, как генерировать токен SAS для большого двоичного объекта, вы можете обратиться к официальному образцу кода Начало работы с сигнатурами общего доступа (SAS)

1 голос
/ 04 июня 2019

Я добавил, а затем удалил комментарий об использовании HttpClient.Timeout, потому что я думаю, что, хотя это может решить проблему, есть проблема с дизайном, который вы используете. Вы используете запрос POST для получения ресурса. Вы действительно должны использовать запрос GET. Обычно это работает так, что вы бы назвали что-то вроде

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

где {file_name} - имя файла, который вы хотите загрузить. Служба обычно знает информацию об учетной записи хранения, поэтому вам не потребуется тело запроса, которое у вас есть в данный момент. Возможно, вы хотите, чтобы служба не зависела от того, с какой учетной записи хранения загружать данные, но я думаю, что это довольно маловероятно.

Мне также кажется необходимым отметить, что если вы собираетесь продолжать отправлять информацию об учетной записи хранения по сети, вам нужно использовать HTTPS вместо HTTP, поскольку в настоящее время вы отправляете ключ учетной записи хранения. в текстовом виде.

...