Как получить размер файла из заголовков http

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


person Community    schedule 23.09.2008    source источник


Ответы (4)


Да, при условии, что 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 отсутствует в ответе сервера, единственный способ определить размер содержимого на сервере - загрузить его. Поскольку это не особенно надежно, большинство серверов будут включать эту информацию.

person mdb    schedule 23.09.2008
comment
Если вы используете using, он автоматически удаляет его. msdn.microsoft.com/en-us/library /yh598w02(v=vs.110).aspx - person justderb; 17.04.2013
comment
Еще одно замечание: если вы используете это для очень больших файлов, int недостаточно, вам нужно использовать long ContentLength; и long.TryParse(xxx) для поддержки возвращаемого значения размером более 2,14 ГБ. - person Preston; 16.10.2015
comment
Не приведет ли включение HTTP-сжатия к фактическому размеру файла? - person Justin; 18.07.2016
comment
Я использую этот метод, чтобы узнать размер этой ссылки: http://ipv4.download.thinkbroadband.com/200MB.zip, но получаю ошибку 403! Зачем? - person Behzad; 21.04.2020

Можно ли это сделать с помощью заголовков 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 вручную.

person Konrad Rudolph    schedule 23.09.2008
comment
Разве resp.ContentLength выше не даст вам длину ответа HEAD, а не длину файла, который вы хотели получить, sizeof? - person Adam Nofsinger; 19.04.2011
comment
@Adam Нет. В документации сказано: «Свойство ContentLength содержит значение заголовка Content-Length, возвращаемого с ответом». - person Konrad Rudolph; 19.04.2011
comment
Убедитесь, что вы вызываете resp.Close (), иначе вы можете столкнуться с ошибками тайм-аута при одновременном выполнении нескольких запросов (мой третий запрос был отключен в цикле foreach, который был решен путем закрытия каждого ответа) - person Eric Smith; 26.03.2013
comment
@Eric Фактически, вы должны использовать здесь блок Using или реализовать одноразовый шаблон для явного управления временем жизни ресурса. Вызов Close вручную недостаточно, если вы не уверены, что это всегда происходит, даже в случае ошибки. - person Konrad Rudolph; 26.03.2013
comment
@KonradRudolph Вы абсолютно правы. Вызов Close () исправил мою ошибку, пока я тестировал это, но использование блока - правильный способ сделать это. Дерп. - person Eric Smith; 26.03.2013
comment
@KonradRudolph, к сведению, ContentLength возвращает long. Ничего страшного, но на всякий случай, если вы захотите это исправить. - person gunr2171; 02.05.2013

Обратите внимание, что не каждый сервер принимает 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);
            }
        }
    }
}
person Daria    schedule 18.07.2018
comment
Хорошее решение, но не каждый сервер разрешает запросы диапазона контента. - person Phani Rithvij; 29.12.2019

person    schedule
comment
Это отличное решение, особенно если вы уже используете WebClient для загрузки файла и просто хотите сначала добавить проверку длины файла. - person ScottFoster1000; 22.10.2018