C # URL이 있는지 / 유효한지 어떻게 확인할 수 있습니까?


117

저는 Yahoo!에서 주식 기호를 조회하는 Visual C # 2005에서 간단한 프로그램을 만들고 있습니다. Finance는 기록 데이터를 다운로드 한 다음 지정된 종목 기호에 대한 가격 기록을 플로팅합니다.

데이터를 수집하는 데 필요한 정확한 URL을 알고 있으며 사용자가 기존 시세 기호 (또는 Yahoo! Finance의 데이터가있는 하나 이상)를 입력하면 완벽하게 작동합니다. 그러나 프로그램이 존재하지 않는 웹 페이지에서 데이터를 가져 오려고 할 때 사용자가 시세 기호를 구성하면 런타임 오류가 발생합니다.

WebClient 클래스를 사용하고 있으며 DownloadString 함수를 사용하고 있습니다. WebClient 클래스의 다른 모든 멤버 함수를 살펴 보았지만 URL을 테스트하는 데 사용할 수있는 내용이 보이지 않았습니다.

어떻게 할 수 있습니까?


1
C # 2.0 (VS2005) 사용을 표시하도록 업데이트 됨
Marc Gravell

답변:


110

"HEAD"를 발행 할 수 있습니다."GET"대신 요청을 있습니까?

(편집)-lol! 이전에이 작업을 수행것 같습니다 !; rep-garnering의 비난을 피하기 위해 위키로 변경되었습니다. 따라서 콘텐츠 다운로드 비용없이 URL을 테스트하려면 :

// using MyClient from linked post
using(var client = new MyClient()) {
    client.HeadOnly = true;
    // fine, no content downloaded
    string s1 = client.DownloadString("http://google.com");
    // throws 404
    string s2 = client.DownloadString("http://google.com/silly");
}

당신은 try/ catch주위에서 DownloadString오류를 확인합니다. 오류가 없습니까? 존재한다 ...


C # 2.0 (VS2005) :

private bool headOnly;
public bool HeadOnly {
    get {return headOnly;}
    set {headOnly = value;}
}

using(WebClient client = new MyClient())
{
    // code as before
}

FWIW-단순히 HTTP 메서드를 변경하기 때문에 문제가 실제로 해결되는지 확실하지 않습니다 (다른 동작 클라이언트 측 제외). 서버의 응답은 논리가 어떻게 코딩되는지에 따라 크게 달라지며 주가와 같은 동적 서비스에 적합하지 않을 수 있습니다. 정적 리소스 (예 : 이미지, 파일 등)의 경우 HEAD는 일반적으로 서버에 구워지기 때문에 광고 된대로 작동합니다. 초점이 일반적으로 POST 및 GET에 있기 때문에 많은 프로그래머가 명시 적으로 HEAD 요청을하지 않습니다. YMMV
David Taylor

답을 고르는 데 시간이 너무 오래 걸려서 죄송합니다 ... 학교와 일에 방해가되어이 게시물을 잊어 버렸습니다. 부수적으로 'var'유형이없는 Visual Studio 2005를 사용하고 있기 때문에 솔루션을 제대로 작동시킬 수 없습니다. 몇 달 동안이 프로젝트를 수행하지 않았지만 그 사실에 대한 간단한 수정이 있습니까? 또한 솔루션을 구현하려고 할 때 'get'및 'set'정의에 코드가없는 HeadOnly 속성을 정의하려고 시도한 것이 화가났다는 것을 기억합니다. 아니면 내가 뭔가 잘못하고 있었을 수도 있습니다. 그래도 도와 ​​주셔서 감사합니다!
Daniel Waltrip

MyClient 는 무엇입니까 ?
Kiquenet

@Kiquenet 본문에 링크가 있습니다. stackoverflow.com/questions/153451/…
Marc Gravell

136

다음은이 솔루션의 또 다른 구현입니다.

using System.Net;

///
/// Checks the file exists or not.
///
/// The URL of the remote file.
/// True : If the file exits, False if file not exists
private bool RemoteFileExists(string url)
{
    try
    {
        //Creating the HttpWebRequest
        HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
        //Setting the Request method HEAD, you can also use GET too.
        request.Method = "HEAD";
        //Getting the Web Response.
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        //Returns TRUE if the Status code == 200
        response.Close();
        return (response.StatusCode == HttpStatusCode.OK);
    }
    catch
    {
        //Any exception will returns false.
        return false;
    }
}

출처 : http://www.dotnetthoughts.net/2009/10/14/how-to-check-remote-file-exists-using-c/


2
이 코드를 사용하여 여러 이미지가 존재하는지 확인하고 있으며 매우 느립니다 (URL 당 몇 초). 누군가 이것이이 코드의 문제인지 아니면 이런 종류의 호출을 할 때 삶의 사실인지 알고 있습니까?
ssmith

@ssmith 코드 속도를 높일 수있는 한 가지 방법은 아직 시도하지 않은 경우 Parallel.Foreach 루프에서 확인하는 것입니다. 내 URL 테스트 앱이 훨씬 빨라졌습니다.
Jack Fairfield

3
이 물건은 DisposedObject를 반환합니다 (response.StatusCode == HttpStatusCode.OK); 사용하여 포장
Lapenkov 블라디미르을

1
위 코드에 문제가 있습니다. 만약 당신이 response.Close (); 그러면 response.StatusCode를 확인할 수 없습니다. 닫히면 예외가 발생합니다.
Renascent

@ssmith 어떤 방법이 훨씬 빠릅니까?
Kiquenet

36

이러한 솔루션은 꽤 좋지만 200 OK 이외의 다른 상태 코드가있을 수 있다는 사실을 잊고 있습니다. 이것은 상태 모니터링 등을 위해 프로덕션 환경에서 사용한 솔루션입니다.

URL 리디렉션 또는 대상 페이지에 다른 조건이있는 경우이 메서드를 사용하면 반환이 true가됩니다. 또한 GetResponse ()는 예외를 throw하므로 이에 대한 StatusCode를 얻지 못합니다. 예외를 트랩하고 ProtocolError를 확인해야합니다.

400 또는 500 상태 코드는 false를 반환합니다. 다른 모든 것은 사실을 반환합니다. 이 코드는 특정 상태 코드에 대한 요구에 맞게 쉽게 수정할 수 있습니다.

/// <summary>
/// This method will check a url to see that it does not return server or protocol errors
/// </summary>
/// <param name="url">The path to check</param>
/// <returns></returns>
public bool UrlIsValid(string url)
{
    try
    {
        HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;
        request.Timeout = 5000; //set the timeout to 5 seconds to keep the user from waiting too long for the page to load
        request.Method = "HEAD"; //Get only the header information -- no need to download any content

        using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
            int statusCode = (int)response.StatusCode;
            if (statusCode >= 100 && statusCode < 400) //Good requests
            {
                return true;
            }
            else if (statusCode >= 500 && statusCode <= 510) //Server Errors
            {
                //log.Warn(String.Format("The remote server has thrown an internal error. Url is not valid: {0}", url));
                Debug.WriteLine(String.Format("The remote server has thrown an internal error. Url is not valid: {0}", url));
                return false;
            }
        }
    }
    catch (WebException ex)
    {
        if (ex.Status == WebExceptionStatus.ProtocolError) //400 errors
        {
            return false;
        }
        else
        {
            log.Warn(String.Format("Unhandled status [{0}] returned for url: {1}", ex.Status, url), ex);
        }
    }
    catch (Exception ex)
    {
        log.Error(String.Format("Could not test url {0}.", url), ex);
    }
    return false;
}

1
3xx 범위의 일부 상태 코드는 실제로 오류가 발생합니다. 예를 들어 304 Not Modified이 경우 catch 블록에서 처리해야합니다
RobV

3
다만이 방법 풀 - 네 - 머리 아웃 문제가 발생 : HttpWebRequest당신이하지 않으면 그것을 좋아하지 않는 당신이 다른 다운로드 아무것도 시도하기 전에 개체를. 그것을 찾는 데 몇 시간이 걸렸습니다! .Close()response
jbeldock 2013-08-12

4
HttpWebResponse객체 usingIDisposable 연결을 닫는 것을 보장하기 때문에 블록 으로 묶어야 합니다. 이로 인해 @jbeldock이 직면 한 문제가 발생할 수 있습니다.
Habib 2013 년

2
그것은 브라우저에서 잘 작동하는 URL에 404 Not Founds를 던지고 있습니다 ...?
Michael Tranchida

@MichaelTranchida 웹 서버는 지원되지 않는 메소드를 발행 할 때 404로 유명합니다. 귀하의 경우에는 Head해당 리소스에서 지원되지 않을 Get수 있습니다. 대신 405를 던 졌어 야합니다.
Sriram Sakthivel

9

질문을 올바르게 이해했다면 다음과 같은 작은 방법을 사용하여 URL 테스트 결과를 얻을 수 있습니다.

WebRequest webRequest = WebRequest.Create(url);  
WebResponse webResponse;
try 
{
  webResponse = webRequest.GetResponse();
}
catch //If exception thrown then couldn't get response from address
{
  return 0;
} 
return 1;

위 코드를 메서드에 래핑하고이를 사용하여 유효성 검사를 수행 할 수 있습니다. 이 질문에 대한 답변이 되었기를 바랍니다.


1
예, 아마도 서로 다른 경우 (TCP 연결 실패-호스트가 연결을 거부 함, 5xx-치명적인 일이 발생 함, 404-리소스를 찾을 수 없음 등)를 구분하여 솔루션을 구체화 할 수 있습니다. WebException의 Status 속성을 살펴보십시오.)
David Taylor

아주 좋은 지적 데이비드! 그러면 오류를보다 정확하게 처리 할 수 ​​있도록보다 자세한 피드백이 제공됩니다.
캘린더 소프트웨어

1
감사. 내 요점은이 양파에는 여러 계층이 있으며, 각 계층은 작업에 렌치를 넣을 수 있다는 것입니다 (.Net Framework, DNS Resolution, TCP Connectivity, 대상 웹 서버, 대상 응용 프로그램 등). IMHO 좋은 설계는 정보 피드백과 유용한 진단을 제공하기 위해 서로 다른 고장 조건을 구별 할 수 있어야합니다. HTTP에 이유가있는 상태 코드가 있다는 것을 잊지 마십시오.)
David Taylor

6

이것을 시도하십시오 (System.Net을 사용하는지 확인하십시오) :

public bool checkWebsite(string URL) {
   try {
      WebClient wc = new WebClient();
      string HTMLSource = wc.DownloadString(URL);
      return true;
   }
   catch (Exception) {
      return false;
   }
}

checkWebsite () 함수가 호출되면 전달 된 URL의 소스 코드를 가져 오려고합니다. 소스 코드를 받으면 true를 반환합니다. 그렇지 않으면 거짓을 반환합니다.

코드 예 :

//The checkWebsite command will return true:
bool websiteExists = this.checkWebsite("https://www.google.com");

//The checkWebsite command will return false:
bool websiteExists = this.checkWebsite("https://www.thisisnotarealwebsite.com/fakepage.html");

3

다른 옵션이 있습니다.

public static bool UrlIsValid(string url)
{
    bool br = false;
    try {
        IPHostEntry ipHost = Dns.Resolve(url);
        br = true;
    }
    catch (SocketException se) {
        br = false;
    }
    return br;
}

3
호스트가 있는지 확인하는 데 유용 할 수 있습니다. 질문은 분명히 호스트가 존재하는지 여부에 대해 걱정하지 않습니다. 호스트가 존재하고 정상인 것으로 알려진 경우 잘못된 HTTP 경로를 처리하는 것과 관련이 있습니다 .
binki

3

이 솔루션은 따라하기 쉽습니다.

public static bool isValidURL(string url) {
    WebRequest webRequest = WebRequest.Create(url);
    WebResponse webResponse;
    try
    {
        webResponse = webRequest.GetResponse();
    }
    catch //If exception thrown then couldn't get response from address
    {
        return false ;
    }
    return true ;
}

1
가까운 WebResponse를하는 것을 잊지 마세요, 다른 응답 시간은 당신이 당신의 메서드를 호출 할 때마다 성장할 것이다
Madagaga

3
WebRequest request = WebRequest.Create("http://www.google.com");
try
{
     request.GetResponse();
}
catch //If exception thrown then couldn't get response from address
{
     MessageBox.Show("The URL is incorrect");`
}

1
답변에 대한 설명을 추가하십시오. 코드 전용 답변은 혼란스럽고 미래의 독자에게 도움이되지 않으며 그런 식으로 반대 투표를 유도 할 수 있습니다.
Jesse

2

URL이 유효한 날씨를 결정하는 더 간단한 방법이 있습니다.

if (Uri.IsWellFormedUriString(uriString, UriKind.RelativeOrAbsolute))
{
   //...
}

4
아니요,이 방법은 URL에 실제로 액세스 할 수 있는지 여부를 확인하지 않습니다. 심지어 true를 돌려주는 경우 Uri.IsWellFormedUriString ( " 192.168.1.421 ", ...), 명백하게 잘못된 URL을 사용하는
zhaorufei

2

나는 항상 예외가 처리하는 데 훨씬 느리다는 것을 발견했습니다.

덜 집중적 인 방법이 더 빠르고 더 나은 결과를 얻을 수 있을까요?

public bool IsValidUri(Uri uri)
{

    using (HttpClient Client = new HttpClient())
    {

    HttpResponseMessage result = Client.GetAsync(uri).Result;
    HttpStatusCode StatusCode = result.StatusCode;

    switch (StatusCode)
    {

        case HttpStatusCode.Accepted:
            return true;
        case HttpStatusCode.OK:
            return true;
         default:
            return false;
        }
    }
}

그런 다음 다음을 사용하십시오.

IsValidUri(new Uri("http://www.google.com/censorship_algorithm"));

1

웹 서버는 요청의 결과를 나타내는 HTTP 상태 코드로 응답합니다. 예를 들어 200 (때로는 202)은 성공, 404-찾을 수 없음 등 ( 여기 참조) )을 의미합니다. URL의 서버 주소 부분이 정확하고 소켓 시간 초과가 발생하지 않는다고 가정하면 예외는 HTTP 상태 코드가 200이 아니라는 것을 알리는 것일 수 있습니다. 예외 클래스를 확인하고 예외가 전달되는지 확인하는 것이 좋습니다. HTTP 상태 코드.

IIRC-문제의 호출에서 WebException 또는 하위 항목이 발생합니다. 클래스 이름을 확인하여 어떤 것을 확인하고 조건을 트랩하기 위해 try 블록에서 호출을 래핑합니다.


2
실제로 200-299 범위의 모든 것은 성공을 의미합니다. IIRC
Marc Gravell

마크, 당신 말이 맞아요. 나는 의도적으로 "오류 등급"개념 (예 : 5xx, 4xx, 3xx, 2xx 등)에 들어가는 것을 피했습니다. 이는 완전히 다른 웜 캔을 열기 때문입니다. 표준 코드 (200, 302, 404, 500 등)를 처리하는 것조차 코드를 완전히 무시하는 것보다 훨씬 낫습니다.
David Taylor

1

이미 주어진 예제에 이어 다음과 같이 사용하여 응답을 래핑하는 것이 가장 좋습니다.

    public bool IsValidUrl(string url)
    {
         try
         {
             var request = WebRequest.Create(url);
             request.Timeout = 5000;
             request.Method = "HEAD";

             using (var response = (HttpWebResponse)request.GetResponse())
             {
                response.Close();
                return response.StatusCode == HttpStatusCode.OK;
            }
        }
        catch (Exception exception)
        { 
            return false;
        }
   }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.