Я хочу получить размер файла http: /.../ перед его загрузкой. Файл может быть веб-страницей, изображением или медиафайлом. Можно ли это сделать с помощью заголовков HTTP? Как загрузить только HTTP-заголовок файла?





Can this be done with HTTP headers?
Да, это правильный путь. Если информация предоставлена, она в заголовке как 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 вручную.
@Adam Нет. В документации говорится: «Свойство ContentLength содержит значение заголовка Content-Length, возвращаемого с ответом».
Убедитесь, что вы вызываете resp.Close (), иначе вы можете столкнуться с ошибками тайм-аута при одновременном выполнении нескольких запросов (мой третий запрос был отключен в цикле foreach, который был решен путем закрытия каждого ответа)
@Eric На самом деле вы должны использовать здесь блок Using или реализовать одноразовый шаблон для явного управления временем жизни ресурса. Вызов Close вручную недостаточно, если вы не уверены, что произойдет всегда, даже в случае ошибки.
@KonradRudolph Вы абсолютно правы. Вызов Close () исправил мою ошибку, пока я тестировал это, но использование блока - правильный способ сделать это. Дерп.
@KonradRudolph, к сведению, ContentLength возвращает long. Ничего страшного, но на всякий случай, если вы захотите это исправить.
Да, при условии, что 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 отсутствует в ответе сервера, единственный способ определить размер содержимого на сервере - загрузить его. Поскольку это не особенно надежно, большинство серверов будут включать эту информацию.
Если вы используете using, он автоматически удаляется. msdn.microsoft.com/en-us/library/yh598w02(v=vs.110).aspx
Еще одно замечание: если вы используете это для очень больших файлов, int недостаточно, вам нужно использовать long ContentLength; и long.TryParse(xxx) для поддержки возвращаемого значения размером более 2,14 ГБ.
Не приведет ли включение HTTP-сжатия к фактическому размеру файла?
Я использую этот метод, чтобы узнать размер этой ссылки: http://ipv4.download.thinkbroadband.com/200MB.zip, но получаю ошибку 403! Почему?
WebClient webClient = new WebClient();
webClient.OpenRead("http://stackoverflow.com/robots.txt");
long totalSizeBytes= Convert.ToInt64(webClient.ResponseHeaders["Content-Length"]);
Console.WriteLine((totalSizeBytes));
Это отличное решение, особенно если вы уже используете WebClient для загрузки файла и просто хотите сначала добавить проверку длины файла.
Обратите внимание, что не каждый сервер принимает запросы 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);
}
}
}
}
Хорошее решение, но не каждый сервер разрешает запросы диапазона контента.
Разве приведенный выше
resp.ContentLengthне даст вам длину ответа HEAD, а не длину файла, который вы хотели получить, sizeof?