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

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

Ответ 1

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

Ответ 2

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

Ответ 3

WebClient webClient = new WebClient();
webClient.OpenRead("http://stackoverflow.com/robots.txt");
long totalSizeBytes= Convert.ToInt64(webClient.ResponseHeaders["Content-Length"]);
Console.WriteLine((totalSizeBytes));

Ответ 4

Обратите внимание, что не каждый сервер принимает запросы HTTP HEAD. Один из альтернативных подходов для получения размера файла состоит в том, чтобы сделать HTTP GET вызов серверу, запрашивающему только часть файла, чтобы размер ответа был небольшим, и получить размер файла из метаданных, которые возвращаются как часть заголовка содержимого ответа.

Стандарт System.Net.Http.HttpClient может быть использован для достижения этой цели. Частичное содержимое запрашивается путем установки диапазона байтов в заголовке сообщения запроса следующим образом:

    request.Headers.Range = new RangeHeaderValue(startByte, endByte)

Сервер отвечает сообщением, содержащим запрашиваемый диапазон, а также весь размер файла. Эта информация возвращается в заголовке содержимого ответа (response.Content.Header) с ключом "Диапазон содержимого".

Вот пример диапазона содержимого в заголовке содержимого ответного сообщения:

    {
       "Key": "Content-Range",
       "Value": [
         "bytes 0-15/2328372"
       ]
    }

В этом примере значение заголовка подразумевает, что ответ содержит байты от 0 до 15 (т.е. всего 16 байтов), а размер файла составляет 2 388 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);
            }
        }
    }
}