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

StackOverflow https://stackoverflow.com/questions/153451

  •  03-07-2019
  •  | 
  •  

Вопрос

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

Я проверил WebResponse.ContentType, но его ценность всегда null.

У кого-нибудь есть какие-нибудь идеи, что могло быть причиной?

Это было полезно?

Решение

Учитывая ваше обновление, вы можете сделать это, изменив .Метод в 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;
}

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

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

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

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

Вы могли бы отправить первый запрос с помощью глагола HEAD и проверить заголовок ответа content-type?[редактировать] Похоже, вам все же придется использовать 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>

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

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

Я использовал DownloadDataAsync() из этого класса-оболочки, и мне не удалось получить content-type из 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;
    }
}

Вот метод, использующий 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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top