如何检查System.Net.WebClient.DownloadData是否正在下载二进制文件?

我正在尝试使用WebClient使用WinForms应用程序从Web下载文件。 但是,我真的只想下载HTML文件。 我想要忽略的任何其他类型。

我检查了WebResponse.ContentType ,但它的值始终为null

任何人都知道原因是什么?

鉴于您的更新,您可以通过更改GetWebRequest中的.Method来执行此操作:

 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()时检查标头,如果它不是您想要的,可能会抛出exception:

 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属性在inheritance类中定义。 例如,在HttpWebRequest对象中,重载此方法以提供内容类型标头。 我不确定WebClient正在使用什么WebResponse实例。 如果您只想要HTML文件,最好直接使用HttpWebRequest对象。

您可以使用HEAD谓词发出第一个请求,并检查内容类型响应标头? [编辑]看起来你不得不为此使用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个字符读入字符串,然后查看是否包含子字符串

另请注意,这有点浪费,因为在决定是否需要之前,您将始终传输完整文件。 要解决这个问题,切换到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; } } 

这是一个使用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;