system.net.webclient.downloadData가 이진 파일을 다운로드하는지 확인하는 방법은 무엇입니까?

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

  •  03-07-2019
  •  | 
  •  

문제

나는 사용하려고합니다 WebClient Winforms 응용 프로그램을 사용하여 웹에서 파일을 다운로드하려면 그러나 실제로 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 ()를 재정의 할 때 헤더를 확인할 수 있으며, 원하는 경우 예외를 던질 수 있습니다.

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 객체 에서이 메소드는 콘텐츠 유형 헤더를 제공하기 위해 과부하됩니다. WebClient가 사용하는 Webresponse의 인스턴스는 확실하지 않습니다. HTML 파일 만 원한다면 HTTPWebRequest 객체를 직접 사용하는 것이 가장 좋습니다.

헤드 동사로 첫 번째 요청을 발행하고 내용 유형 응답 헤더를 확인할 수 있습니까? [편집] 그래도 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

서버가 반환하는 것이 보장되지 않으므로 컨텐츠 유형 헤더의 존재를 확인해야합니다 (대부분의 최신 HTTP 서버에는 항상 포함되어 있지만). 컨텐츠 유형 헤더가없는 경우 다른 HTML 감지 방법으로 돌아갈 수 있습니다 (예 : 파일을 열고, 첫 1k 문자 등을 문자열에 읽고, 기판이 포함되어 있는지 확인할 수 있습니다.u003Chtml>

또한 원하는지 여부를 결정하기 전에 항상 전체 파일을 전송하므로 이것은 약간 낭비입니다. 이를 해결하려면 Net.httpwebrequest/Response 클래스로 전환하면 도움이 될 수 있지만 추가 코드가 가치가 있는지 여부는 응용 프로그램에 따라 다릅니다 ...

명확하지 않은 것에 대해 사과드립니다. 웹 클리어를 확장하는 래퍼 클래스를 썼습니다. 이 래퍼 클래스에서 쿠키 컨테이너를 추가하고 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;
    }
}

다음은 HTTP가 위에 구축 된 TCP를 사용하는 방법입니다. 연결시 또는 시간 초과 후 (밀리 초) 후에 반환되므로 상황에 따라 값을 변경해야 할 수 있습니다.

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