web-dev-qa-db-fra.com

Comment obtenir la taille du fichier à partir des en-têtes http

Je souhaite obtenir la taille d'un fichier http: /.../ avant de le télécharger. Le fichier peut être une page Web, une image ou un fichier multimédia. Cela peut-il être fait avec des en-têtes HTTP? Comment télécharger uniquement l'en-tête HTTP du fichier?

62
Greg

Oui, en supposant que le serveur HTTP avec lequel vous parlez prend en charge/autorise ceci:

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;
}

Si l'utilisation de la méthode HEAD n'est pas autorisée ou si l'en-tête Content-Length n'est pas présent dans la réponse du serveur, la seule façon de déterminer la taille du contenu sur le serveur est de le télécharger. Comme ce n'est pas particulièrement fiable, la plupart des serveurs incluront ces informations.

91
mdb

Cela peut-il être fait avec des en-têtes HTTP?

Oui, c'est la voie à suivre. Si les informations sont fournies, elles se trouvent dans l'en-tête sous la forme Content-Length. Notez cependant que ce n'est pas nécessairement le cas.

Le téléchargement de l'en-tête uniquement peut être effectué à l'aide d'une requête HEAD au lieu de GET. Peut-être que le code suivant aide:

HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://example.com/");
req.Method = "HEAD";
long len;
using(HttpWebResponse resp = (HttpWebResponse)(req.GetResponse()))
{
    len = resp.ContentLength;
}

Remarquez la propriété de la longueur du contenu sur l'objet HttpWebResponse - pas besoin d'analyser le Content-Length en-tête manuellement.

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

Notez que tous les serveurs n'acceptent pas HTTP HEAD demandes. Une autre approche pour obtenir la taille du fichier consiste à créer un HTTP GET appel au serveur ne demandant qu'une partie du fichier pour garder la réponse petite et récupérer la taille du fichier à partir des métadonnées renvoyées dans le cadre de l'en-tête du contenu de la réponse.

Le standard System.Net.Http.HttpClient peut être utilisé pour cela. Le contenu partiel est demandé en définissant une plage d'octets sur l'en-tête du message de demande comme:

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

Le serveur répond avec un message contenant la plage demandée ainsi que la taille totale du fichier. Ces informations sont renvoyées dans l'en-tête du contenu de la réponse (response.Content.Header) avec la clé "Content-Range".

Voici un exemple de la plage de contenu dans l'en-tête du contenu du message de réponse:

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

Dans cet exemple, la valeur d'en-tête implique que la réponse contient des octets de 0 à 15 (c'est-à-dire 16 octets au total) et le fichier est de 2328372 octets dans son intégralité.

Voici un exemple d'implémentation de cette méthode:

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);
            }
        }
    }
}
1
Daria