Как получить размер файла из заголовков http
-
02-07-2019 - |
Вопрос
Я хочу получить размер http:/.../файла перед его загрузкой.Файл может быть веб-страницей, изображением или медиафайлом.Можно ли это сделать с помощью HTTP-заголовков?Как загрузить только HTTP-заголовок файла?
Решение
Да, при условии, что HTTP-сервер, с которым вы разговариваете, поддерживает/разрешает это:
public long GetFileSize(string url)
{
long result = -1;
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
req.Method = "HEAD";
using (System.Net.WebResponse resp = req.GetResponse())
{
if (long.TryParse(resp.Headers.Get("Content-Length"), out long ContentLength))
{
result = ContentLength;
}
}
return result;
}
Если использование метода HEAD не разрешено или заголовок Content-Length отсутствует в ответе сервера, единственный способ определить размер контента на сервере — загрузить его.Поскольку это не особенно надежно, большинство серверов включают эту информацию.
Другие советы
Можно ли это сделать с помощью HTTP-заголовков?
Да, это правильный путь. Если информация предоставлена, она есть в шапке, как и Content-Length
.Однако обратите внимание, что это не обязательно так.
Загрузить только заголовок можно с помощью HEAD
запрос вместо GET
.Возможно, поможет следующий код:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://example.com/");
req.Method = "HEAD";
long len;
using(HttpWebResponse resp = (HttpWebResponse)(req.GetResponse()))
{
len = resp.ContentLength;
}
Обратите внимание на свойство длины содержимого в HttpWebResponse
объект – нет необходимости анализировать Content-Length
заголовок вручную.
WebClient webClient = new WebClient();
webClient.OpenRead("http://stackoverflow.com/robots.txt");
long totalSizeBytes= Convert.ToInt64(webClient.ResponseHeaders["Content-Length"]);
Console.WriteLine((totalSizeBytes));
Обратите внимание, что не каждый сервер принимает HTTP HEAD
Запросы.Один из альтернативных подходов к получению размера файла — создать HTTP GET
вызовите сервер, запрашивая только часть файла, чтобы сохранить небольшой ответ и получить размер файла из метаданных, которые возвращаются как часть заголовка содержимого ответа.
Стандарт System.Net.Http.HttpClient
может быть использован для достижения этой цели.Частичное содержимое запрашивается путем установки диапазона байтов в заголовке сообщения запроса следующим образом:
request.Headers.Range = new RangeHeaderValue(startByte, endByte)
Сервер отвечает сообщением, содержащим запрошенный диапазон, а также весь размер файла.Эта информация возвращается в заголовке содержимого ответа (response.Content.Header
) с ключом «Content-Range».
Вот пример диапазона содержимого в заголовке содержимого ответного сообщения:
{
"Key": "Content-Range",
"Value": [
"bytes 0-15/2328372"
]
}
В этом примере значение заголовка подразумевает, что ответ содержит байты от 0 до 15 (т. е. всего 16 байт), а размер файла составляет 2 328 372 байта.
Вот пример реализации этого метода:
public static class HttpClientExtensions
{
public static async Task<long> GetContentSizeAsync(this System.Net.Http.HttpClient client, string url)
{
using (var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url))
{
// In order to keep the response as small as possible, set the requested byte range to [0,0] (i.e., only the first byte)
request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(from: 0, to: 0);
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
if (response.StatusCode != System.Net.HttpStatusCode.PartialContent)
throw new System.Net.WebException($"expected partial content response ({System.Net.HttpStatusCode.PartialContent}), instead received: {response.StatusCode}");
var contentRange = response.Content.Headers.GetValues(@"Content-Range").Single();
var lengthString = System.Text.RegularExpressions.Regex.Match(contentRange, @"(?<=^bytes\s[0-9]+\-[0-9]+/)[0-9]+$").Value;
return long.Parse(lengthString);
}
}
}
}