C # Bir URL'nin varlığını / geçerli olup olmadığını nasıl kontrol edebilirim?


117

Yahoo! üzerinde bir hisse senedi simgesi arayan visual c # 2005'te basit bir program yapıyorum. Finans, geçmiş verileri indirir ve ardından belirtilen hisse senedi sembolü için fiyat geçmişini çizer.

Verileri elde etmek için ihtiyacım olan URL'yi tam olarak biliyorum ve kullanıcı mevcut bir hisse senedi simgesi (veya en azından Yahoo! Finance'daki verilerle birlikte en az birini) girerse, mükemmel şekilde çalışıyor. Ancak, program var olmayan bir web sayfasından veri almaya çalıştığı için kullanıcı bir kayan yazı sembolü oluşturduğunda bir çalışma zamanı hatası alıyorum.

WebClient sınıfını ve DownloadString işlevini kullanıyorum. WebClient sınıfının diğer tüm üye işlevlerine baktım, ancak bir URL'yi test etmek için kullanabileceğim hiçbir şey görmedim.

Bunu nasıl yapabilirim?


1
C # 2.0 (VS2005) kullanımını gösterecek şekilde güncellendi
Marc Gravell

Yanıtlar:


110

Bir sorunu olabilir "BAŞ" bir "GET" yerine isteği?

(değiştir) - lol! Ben gibi görünüyor ettik daha önce yapmış !; temsilci toplama suçlamalarını önlemek için wiki olarak değiştirildi. Dolayısıyla, içeriği indirme maliyeti olmadan bir URL'yi test etmek için:

// 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");
}

Verirsin try/ catchetrafında DownloadStringhatalarını kontrol etmek; hata yok? Var...


C # 2.0 (VS2005) ile:

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

ve

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

FWIW - Yalnızca HTTP yöntemini değiştirdiğiniz için, sorunun gerçekten çözülüp çözülmediğinden emin değilsiniz (belki farklı davranış istemci tarafı dışında). Sunucudan gelen yanıt, büyük ölçüde mantığın nasıl kodlandığına bağlı olacaktır ve hisse senedi fiyatı gibi dinamik bir hizmet için iyi çalışmayabilir. Statik kaynaklar için (örn. Resimler, dosyalar vb.) HEAD genellikle sunucuda pişirildiği için reklamı yapıldığı gibi çalışır. Odak noktası normalde POST ve GET olduğu için birçok programcı açıkça HEAD istekleri yapmaz. YMMV
David Taylor

Bu kadar uzun bir cevap aldığım için özür dilerim ... Okul ve iş beni şaşırttı ve bu yazıyı biraz unuttum. Bir yan not olarak, çözümünüzü tam olarak çalıştıramadım çünkü 'var' tipine sahip olmayan Visual Studio 2005 kullanıyorum. Bu proje üzerinde aylardır çalışmadım, ancak bu gerçek için basit bir düzeltme var mı? Ayrıca çözümünüzü uygulamaya çalıştığımda, HeadOnly özelliğini 'get' ve 'set' tanımlarında kod olmadan tanımlamaya çalıştığım için bana kızdığını hatırlıyorum. Ya da belki yanlış bir şey yapıyordum. Yine de yardım için teşekkürler!
Daniel Waltrip

Nedir MyClient ?
Kiquenet

@Kiquenet gövdede buraya bir bağlantı vardır: stackoverflow.com/questions/153451/…
Marc Gravell

136

İşte bu çözümün başka bir uygulaması:

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

Gönderen: http://www.dotnetuverts.net/2009/10/14/how-to-check-remote-file-exists-using-c/


2
Bu kodu, bir grup resmin var olup olmadığını kontrol etmek için kullanıyorum ve oldukça yavaş (URL başına birkaç saniye). Birisi bu kodla ilgili bir sorun mu yoksa bu tür aramalar yaparken hayatın bir gerçeği mi biliyor?
ssmith

@ssmith Kodunuzu hızlandırmanın bir yolu, henüz denemediyseniz Parallel.Foreach döngüsünde kontrol yapmaktır. Url test uygulamamı ÇOK daha hızlı hale getirdi.
Jack Fairfield

3
Bu malzeme, karşılığında DisposedObject'i atar (response.StatusCode == HttpStatusCode.OK); kullanarak sarın
Lapenkov Vladimir

1
Yukarıdaki kodla ilgili bir sorun var. yanıt verirseniz.Close (); o zaman yanıtı kontrol edemezsiniz.StatusCode kapanırken bir istisna atacaktır.
Renascent

@ssmith herhangi bir yöntem çok daha hızlı?
Kiquenet

36

Bu çözümler oldukça iyi, ancak 200 OK dışında başka durum kodları olabileceğini unutuyorlar. Bu, durum izleme vb. İçin üretim ortamlarında kullandığım bir çözüm.

Hedef sayfada bir url yönlendirmesi veya başka bir koşul varsa, bu yöntem kullanılarak dönüş doğru olacaktır. Ayrıca GetResponse () bir istisna atar ve bu nedenle bunun için bir Durum Kodu alamazsınız. İstisnayı yakalamanız ve bir Protokol Hatası olup olmadığını kontrol etmeniz gerekir.

Herhangi bir 400 veya 500 durum kodu yanlış döndürür. Diğerlerinin tümü gerçek olur. Bu kod, belirli durum kodlarına yönelik ihtiyaçlarınıza uyacak şekilde kolayca değiştirilebilir.

/// <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 aralığındaki bazı durum kodlarının aslında bir hatanın atılmasına neden olacağını ekleyeceğim, örneğin 304 Değiştirilmedi bu durumda bunu catch bloğunuzda
işlemeniz

3
Sadece bu yaklaşım ile bir çekme-your-saç-out sorunu yaşamış: HttpWebRequestAksi takdirde böyle değil başka indirme şey denemeden önce nesneyi. Onu bulmak saatler sürdü! .Close()response
jbeldock

4
HttpWebResponseNesne , aynı zamanda bağlantının kapatılmasını da sağlayacak şekilde uygulandığı için blok içine alınmalıdırusingIDisposable . Bu, @jbeldock'un karşılaştığı sorunlara neden olabilir.
Habib

2
Bir tarayıcıda düzgün çalışan url'lere 404 Bulunamadı atıyor ...?
Michael Tranchida

@MichaelTranchida Web sunucuları, desteklenmeyen bir yöntem yayınladığınızda 404 ile ünlüdür. Sizin durumunuzda Head, bu kaynakta desteklenmiyor Getolabilir. Onun yerine 405 atmalıydı.
Sriram Sakthivel

9

Sorunuzu doğru anlarsam, URL testinizin sonuçlarını size vermek için bunun gibi küçük bir yöntem kullanabilirsiniz:

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;

Yukarıdaki kodu bir yönteme sarabilir ve doğrulama gerçekleştirmek için kullanabilirsiniz. Umarım bu sorduğunuz soruyu yanıtlar.


1
Evet, belki de farklı durumlar arasında ayrım yaparak çözümü iyileştirebilirsiniz (TCP bağlantı hatası - ana bilgisayar bağlantıyı reddediyor, 5xx - Önemli bir şey oldu, 404 - Kaynak bulunamadı vb.). WebException'ın Status özelliğine bir göz atın;)
David Taylor

Çok iyi nokta David! Bu, hatayı daha akıllıca ele alabilmemiz için bize daha ayrıntılı geri bildirim sağlayacaktır.
Takvim Yazılımı

1
Teşekkürler. Demek istediğim, bu soğanda her biri işlere bir anahtar atabilecek birkaç katman var (.Net Framework, DNS Çözünürlüğü, TCP Bağlantısı, hedef Web Sunucusu, hedef uygulama vb.). IMHO iyi bir tasarım, bilgilendirici geri bildirim ve kullanılabilir teşhis sağlamak için farklı arıza koşullarını ayırt edebilmelidir. Ayrıca HTTP'nin bir nedenden dolayı durum kodlarına sahip olduğunu da unutmayalım;)
David Taylor

6

Bunu deneyin (System.Net kullandığınızdan emin olun):

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

CheckWebsite () işlevi çağrıldığında, kendisine iletilen URL'nin kaynak kodunu almaya çalışır. Kaynak kodunu alırsa, doğru döndürür. Değilse, yanlış döndürür.

Kod Örneği:

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

İşte başka bir seçenek

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
Bu, bir ana bilgisayarın olup olmadığını kontrol etmek için yararlı olabilir. Soru, ev sahibinin var olup olmadığı konusunda endişeli değil. Ana bilgisayarın var olduğu ve iyi olduğu bilindiğinden, kötü bir HTTP yolunu ele almakla ilgilidir .
binki

3

Bu çözümü takip etmek kolay görünüyor:

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'u kapatmayı unutmayın, aksi takdirde yönteminizi her aradığınızda yanıt süresi artacaktır
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
Lütfen cevabınıza bir açıklama ekleyin. Yalnızca kod yanıtları kafa karıştırıcı olma eğilimindedir ve gelecekteki okuyucular için yararlı değildir ve bu şekilde olumsuz oyları çekebilir.
Jesse

2

Bir url'nin geçerli olup olmadığını belirlemenin daha basit bir yolu var.

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

4
Hayır, bu yöntem url'nin gerçekten erişilebilir olup olmadığını kontrol etmez. Açıkça yanlış bir url kullanan Uri.IsWellFormedUriString (" 192.168.1.421 ", ...) olduğunda bile doğru döndürüyor
zhaorufei

2

İstisnaların ele alınmasının her zaman çok daha yavaş olduğunu gördüm.

Belki daha az yoğun bir yol daha iyi, daha hızlı bir sonuç elde edebilir mi?

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

O zaman şunu kullan:

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

1

Web sunucuları, isteğin sonucunu belirten bir HTTP durum kodu ile yanıt verir, örneğin 200 (bazen 202) başarı anlamına gelir, 404 - bulunamadı vb. ( Buraya bakın ). URL'nin sunucu adresi kısmının doğru olduğunu ve bir soket zaman aşımı almadığınızı varsayarsak, istisna büyük olasılıkla size HTTP durum kodunun 200'den farklı olduğunu söyler. İstisna sınıfını kontrol etmenizi ve istisnanın taşıyıp taşımadığını görmenizi öneririm. HTTP durum kodu.

IIRC - Söz konusu çağrı, bir WebException veya nesli atar. Hangisinin olduğunu görmek için sınıf adını kontrol edin ve koşulu yakalamak için çağrıyı bir try bloğuna sarın.


2
Aslında, 200-299 aralığındaki her şey başarı anlamına gelir, IIRC
Marc Gravell

Marc, kesinlikle haklısın. "Hata sınıfı" kavramına (örneğin 5xx, 4xx, 3xx, 2xx vb.) Girmekten kasıtlı olarak kaçındım çünkü bu, diğer bir solucan kutusunu açıyor. Standart kodları (200, 302, 404, 500 vb.) Ele almak bile kodları tamamen görmezden gelmekten çok daha iyidir.
David Taylor

1

Halihazırda verilen örneklerden yola çıkarak, yanıtı bunun gibi bir şekilde paketlemenin en iyi uygulama olduğunu söyleyebilirim.

    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;
        }
   }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.