C#URLが存在する/有効であるかどうかを確認するにはどうすればよいですか?


117

Yahoo!で銘柄記号を検索するビジュアルc#2005で簡単なプログラムを作成しています。ファイナンス、履歴データをダウンロードし、指定されたティッカーシンボルの価格履歴をプロットします。

私はデータを取得するために必要な正確なURLを知っています。ユーザーが既存のティッカーシンボル(またはYahoo!ファイナンスのデータを持つ少なくとも1つ)を入力した場合、それは完全に正常に機能します。ただし、プログラムが存在しないWebページからデータをプルしようとするため、ユーザーがティッカーシンボルを作成すると、実行時エラーが発生します。

WebClientクラスとDownloadString関数を使用しています。WebClientクラスの他のすべてのメンバー関数を調べましたが、URLのテストに使用できるものは何も見つかりませんでした。

これどうやってするの?


1
C#2.0(VS2005)の使用を示すように更新
Marc Gravell

回答:


110

「GET」ではなく「HEAD」リクエストを発行できますか?

(編集)-笑!私はこれを以前にしたことがあるようです!; rep-garneringの非難を避けるためにwikiに変更しました。コンテンツをダウンロードするコストなしで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
デビッドテイラー

答えを選択するのに時間がかかってすみません...私は学校と仕事に横道になり、この投稿を忘れていました。補足として、私は 'var'タイプを持たないVisual Studio 2005を使用しているため、ソリューションをうまく機能させることができませんでした。私はこのプロジェクトに何ヶ月も取り組んでいませんが、その事実に対する簡単な修正はありますか?また、私があなたのソリューションを実装しようとしたとき、「get」および「set」定義にコードなしでHeadOnlyプロパティを定義しようとすることに腹を立てたことを覚えています。あるいは、私は何か間違ったことをしていたのかもしれません。助けてくれてありがとう!
Daniel Waltrip

MyClientとはですか?
Kiquenet

@Kiquenetが身体内のリンクは、あるここに:stackoverflow.com/questions/153451/...
マルク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;
    }
}

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


2
このコードを使用して、画像の束が存在するかどうかを確認しています。非常に遅い(URLごとに数秒)。誰かがこれがこのコードの問題なのか、それともこの種の呼び出しを行うときの現実なのかを知っていますか?
ssmith

@ssmithコードを高速化できる1つの方法は、Parallel.Foreachループでチェックを行っていない場合は、それを試すことです。それは私のURLテストアプリをはるかに速くしました。
ジャックフェアフィールド

3
これにより、DisposedObjectがスローされます(response.StatusCode == HttpStatusCode.OK); ラップイン使用
Lapenkov Vladimir 2018

1
上記のコードに問題があります。あなたがresponse.Close();を行う場合 すると、response.StatusCodeをチェックできません。閉じると例外がスローされます。
Renascent

@ssmith任意の方法をはるかに速く?
Kiquenet

36

これらのソリューションはかなり良いですが、200 OK以外のステータスコードが存在する可能性があることを忘れています。これは、ステータス監視などのために本番環境で使用したソリューションです。

ターゲットページにURLリダイレクトまたはその他の条件がある場合、このメソッドを使用して戻り値はtrueになります。また、GetResponse()は例外をスローするため、そのためのStatusCodeを取得できません。例外をトラップし、ProtocolErrorを確認する必要があります。

400または500のステータスコードはfalseを返します。他のすべてはtrueを返します。このコードは、特定のステータスコードのニーズに合わせて簡単に変更できます。

/// <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の場合、キャッチブロックで処理する必要があります
RobV

3
このアプローチで髪の毛が抜ける問題が発生しました 。他に何かをダウンロードする前にオブジェクトHttpWebRequestがない場合は気に入らないでしょう。それを見つけるのに何時間もかかりました!.Close()response
jbeldock 2013

4
HttpWebResponseオブジェクトusingIDisposable、接続を確実に閉じるように実装するためブロックで囲む必要があります。@jbeldockが直面しているように、これは問題を引き起こす可能性があります。
ハビブ2013

2
ブラウザで正常に動作するURLに404 Not Foundsをスローしています...?
Michael Tranchida、2015年

サポートされていないメソッドを発行した場合、@ MichaelTranchida Webサーバーは404で有名です。あなたの場合Head、そのリソースではサポートされていないGet可能性があります。代わりに405をスローしているはずです。
Sriram Sakthivel、2016年

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プロパティをご覧ください;)
デビッドテイラー、

とても良い点デイビッド!これにより、より詳細なフィードバックが得られ、エラーをより迅速に処理できるようになります。
カレンダーソフトウェア、

1
ありがとう。私のポイントは、このタマネギにはいくつかの層があり、それぞれが作業にレンチを投げることができるということです(.Net Framework、DNS解決、TCP接続、ターゲットWebサーバー、ターゲットアプリケーションなど)。優れた設計では、さまざまな障害状態を識別して、有益なフィードバックと使用可能な診断を提供できる必要があります。また、HTTPに理由コードがあることも忘れないでください;)
デビッドテイラー

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を返します。そうでない場合は、falseを返します。

コード例:

//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 2015年

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を閉じることを忘れないでください。そうしないと、メソッドを呼び出すたびに応答時間が
長くなり

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
回答に説明を追加してください。コードのみの回答は混乱する傾向があり、将来の読者にとって役に立たない傾向があり、そのようにして反対票を集めることができます。
ジェシー

2

URLが有効である天気を判断するより簡単な方法があります。

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

4
いいえ、このメソッドはURLが本当にアクセス可能かどうかをチェックしません。Uri.IsWellFormedUriString( " 192.168.1.421 "、...)がtrueを返す場合でも、明らかに正しくない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

Webサーバーは、リクエストの結果を示すHTTPステータスコードで応答します。たとえば、200(場合によっては202)は成功を意味し、404-見つかりませんなど(ここを参照)。URLのサーバーアドレス部分が正しく、ソケットタイムアウトが発生しない場合、例外はHTTPステータスコードが200以外であることを示していると考えられます。例外のクラスを確認し、例外が発生するかどうかを確認することをお勧めしますHTTPステータスコード。

IIRC-問題の呼び出しはWebExceptionまたは子孫をスローします。クラス名をチェックしてどれを確認し、呼び出しをtryブロックにラップして条件をトラップします。


2
実際には、200〜299の範囲内のものは、成功、IIRC意味
マルクGravell

マーク、あなたは絶対に正しいです。「エラーのクラス」の概念(5xx、4xx、3xx、2xxなど)に入るのは意図的に避けました。これは、ワームの缶を完全に開くためです。標準コード(200、302、404、500など)を処理することも、コードを完全に無視するよりもはるかに優れています。
デビッドテイラー

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.