Как проверить, загружает ли System.Net.WebClient.DownloadData двоичный файл?

Я пытаюсь использовать WebClient для загрузки файла из Интернета с помощью приложения WinForms. Однако я действительно хочу загрузить только HTML-файл. Любой другой тип, который я хочу проигнорировать.

Я проверил WebResponse.ContentType, но его значение всегда null.

Кто-нибудь знает, в чем может быть причина?

Вам нужны изображения, таблицы стилей и JavaScript?

Orion Adrian 30.09.2008 19:06
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
23
1
54 272
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Вы можете отправить первый запрос с помощью глагола HEAD и проверить заголовок ответа типа содержимого? [edit] Похоже, что для этого вам придется использовать HttpWebRequest.

(устарело продолжением OP - см. мой другой ответ о GetWebRequest)

Marc Gravell 01.10.2008 12:50

WebResponse - это абстрактный класс, а свойство ContentType определяется в наследующих классах. Например, в объекте HttpWebRequest этот метод перегружен, чтобы предоставить заголовок типа содержимого. Я не уверен, какой экземпляр WebResponse использует WebClient. Если вам нужны ТОЛЬКО файлы HTML, лучше всего напрямую использовать объект HttpWebRequest.

Ваш вопрос немного сбивает с толку: если вы используете экземпляр класса Net.WebClient, Net.WebResponse не входит в уравнение (кроме того факта, что это действительно абстрактный класс, и вы бы использовали конкретная реализация, такая как HttpWebResponse, как указано в другом ответе).

В любом случае, используя WebClient, вы можете добиться желаемого, сделав что-то вроде этого:

Dim wc As New Net.WebClient()
Dim LocalFile As String = IO.Path.Combine(Environment.GetEnvironmentVariable("TEMP"), Guid.NewGuid.ToString)
wc.DownloadFile("http://example.com/somefile", LocalFile)
If Not wc.ResponseHeaders("Content-Type") Is Nothing AndAlso wc.ResponseHeaders("Content-Type") <> "text/html" Then
    IO.File.Delete(LocalFile)
Else
    '//Process the file
End If

Обратите внимание, что вам необходимо проверить наличие заголовка Content-Type, поскольку сервер не гарантирует его возврат (хотя большинство современных HTTP-серверов всегда включают его). Если заголовок Content-Type отсутствует, вы можете вернуться к другому методу обнаружения HTML, например, открыть файл, прочитать первые 1K символов или около того в строку и посмотреть, содержит ли он подстроку <html>

Также обратите внимание, что это немного расточительно, так как вы всегда будете передавать полный файл, прежде чем решить, хотите вы этого или нет. Чтобы обойти это, переключение на классы Net.HttpWebRequest / Response может помочь, но стоит ли этого дополнительного кода, зависит от вашего приложения ...

Прошу прощения за не очень четкое. Я написал класс-оболочку, расширяющую WebClient. В этом классе-оболочке я добавил контейнер cookie и предоставил свойство тайм-аута для WebRequest.

Я использовал DownloadDataAsync () из этого класса-оболочки, и мне не удалось получить тип содержимого из WebResponse этого класса-оболочки. Мое главное намерение - перехватить ответ и определить, имеет ли он текст / html-характер. Если это не так, я отменю этот запрос.

Мне удалось получить тип содержимого после переопределения метода WebClient.GetWebResponse (WebRequest, IAsyncResult).

Ниже приведен образец моего класса-оболочки:

public class MyWebClient : WebClient
{
    private CookieContainer _cookieContainer;
    private string _userAgent;
    private int _timeout;
    private WebReponse _response;

    public MyWebClient()
    {
        this._cookieContainer = new CookieContainer();
        this.SetTimeout(60 * 1000);
    }

    public MyWebClient SetTimeout(int timeout)
    {
        this.Timeout = timeout;
        return this;
    }

    public WebResponse Response
    {
        get { return this._response; }
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);

        if (request.GetType() == typeof(HttpWebRequest))
        {
            ((HttpWebRequest)request).CookieContainer = this._cookieContainer;
            ((HttpWebRequest)request).UserAgent = this._userAgent;
            ((HttpWebRequest)request).Timeout = this._timeout;
        }

        this._request = request;
        return request;
    }

    protected override WebResponse GetWebResponse(WebRequest request)
    {
        this._response = base.GetWebResponse(request);
        return this._response;
    }

    protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
    {
        this._response = base.GetWebResponse(request, result);
        return this._response;
    }

    public MyWebClient ServerCertValidation(bool validate)
    {
        if (!validate) ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
        return this;
    }
}

В этом случае измените .Method - см. Мой другой ответ.

Marc Gravell 01.10.2008 12:49
Ответ принят как подходящий

Учитывая ваше обновление, вы можете сделать это, изменив .Method в GetWebRequest:

using System;
using System.Net;
static class Program
{
    static void Main()
    {
        using (MyClient client = new MyClient())
        {
            client.HeadOnly = true;
            string uri = "http://www.google.com";
            byte[] body = client.DownloadData(uri); // note should be 0-length
            string type = client.ResponseHeaders["content-type"];
            client.HeadOnly = false;
            // check 'tis not binary... we'll use text/, but could
            // check for text/html
            if (type.StartsWith(@"text/"))
            {
                string text = client.DownloadString(uri);
                Console.WriteLine(text);
            }
        }
    }

}

class MyClient : WebClient
{
    public bool HeadOnly { get; set; }
    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest req = base.GetWebRequest(address);
        if (HeadOnly && req.Method == "GET")
        {
            req.Method = "HEAD";
        }
        return req;
    }
}

В качестве альтернативы вы можете проверить заголовок при переопределении GetWebRespons (), возможно, сгенерировав исключение, если это не то, что вы хотели:

protected override WebResponse GetWebResponse(WebRequest request)
{
    WebResponse resp = base.GetWebResponse(request);
    string type = resp.Headers["content-type"];
    // do something with type
    return resp;
}

Не забывайте XHTML: w3.org/TR/xhtml-media-types/#application-xhtml-xml

bzlm 25.05.2009 14:13

Я не уверен в причине, но, возможно, вы еще ничего не скачали. Это ленивый способ получить тип содержимого удаленного файла / страницы (я не проверял, эффективно ли это в сети. Насколько я знаю, он может загружать огромные куски контента)

        Stream connection = new MemoryStream(""); // Just a placeholder
        WebClient wc = new WebClient();
        string contentType;
        try
        {
            connection = wc.OpenRead(current.Url);
            contentType = wc.ResponseHeaders["content-type"];
        }
        catch (Exception)
        {
            // 404 or what have you
        }
        finally
        {
            connection.Close();
        }

Вот метод, использующий TCP, поверх которого построен http. Он вернется при подключении или по истечении времени ожидания (миллисекунды), поэтому значение может потребоваться изменить в зависимости от вашей ситуации.

var result = false;
try {
    using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) {
        var asyncResult = socket.BeginConnect(yourUri.AbsoluteUri, 80, null, null);
        result = asyncResult.AsyncWaitHandle.WaitOne(100, true);
        socket.Close();
    }
}
catch { }
return result;

Другие вопросы по теме