C # Wie kann ich überprüfen, ob eine URL vorhanden / gültig ist?

117

Ich mache ein einfaches Programm in Visual C # 2005, das ein Aktiensymbol auf Yahoo! Finanzen, lädt die historischen Daten herunter und zeichnet dann den Preisverlauf für das angegebene Tickersymbol.

Ich kenne die genaue URL, die ich zum Erfassen der Daten benötige, und wenn der Benutzer ein vorhandenes Tickersymbol (oder mindestens eines mit Daten auf Yahoo! Finance) eingibt, funktioniert dies einwandfrei. Ich habe jedoch einen Laufzeitfehler, wenn der Benutzer ein Tickersymbol erstellt, da das Programm versucht, Daten von einer nicht vorhandenen Webseite abzurufen.

Ich verwende die WebClient-Klasse und die DownloadString-Funktion. Ich habe alle anderen Mitgliedsfunktionen der WebClient-Klasse durchgesehen, aber nichts gefunden, mit dem ich eine URL testen könnte.

Wie kann ich das machen?

Daniel Waltrip
quelle
1
aktualisiert, um die Verwendung von C # 2.0 (VS2005) anzuzeigen
Marc Gravell

Antworten:

110

Sie könnten eher eine "HEAD" -Anforderung als eine "GET" -Anforderung ausgeben ?

(bearbeiten) - lol! Sieht so aus, als hätte ich das schon mal gemacht ! wurde in das Wiki geändert, um Vorwürfe der Wiederholung zu vermeiden. So testen Sie eine URL ohne die Kosten für das Herunterladen des Inhalts:

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

Sie würden try/ catchum die DownloadStringauf Fehler prüfen; kein Fehler? Es existiert...


Mit C # 2.0 (VS2005):

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

und

using(WebClient client = new MyClient())
{
    // code as before
}
Marc Gravell
quelle
FWIW - Ich bin mir nicht sicher, ob das Problem dadurch wirklich gelöst wird (außer vielleicht auf der Client-Seite mit unterschiedlichem Verhalten), da Sie einfach die HTTP-Methode ändern. Die Antwort vom Server hängt stark davon ab, wie die Logik codiert ist, und funktioniert möglicherweise nicht gut für einen dynamischen Dienst wie den Aktienkurs. Bei statischen Ressourcen (z. B. Bilder, Dateien usw.) funktioniert HEAD normalerweise wie angekündigt, da es in den Server eingebettet ist. Viele Programmierer führen HEAD-Anforderungen nicht explizit aus, da der Fokus normalerweise auf POST und GET liegt. YMMV
David Taylor
Es tut mir leid, dass ich so lange gebraucht habe, um eine Antwort zu finden ... Ich wurde von Schule und Arbeit abgelenkt und habe diesen Beitrag irgendwie vergessen. Als Nebenbemerkung konnte ich Ihre Lösung nicht zum Laufen bringen, da ich Visual Studio 2005 verwende, das nicht den Typ 'var' hat. Ich habe seit Monaten nicht mehr an diesem Projekt gearbeitet, aber gibt es eine einfache Lösung für diese Tatsache? Auch als ich versucht habe, Ihre Lösung zu implementieren, erinnere ich mich, dass es sauer auf mich war, die HeadOnly-Eigenschaft ohne Code in den Definitionen 'get' und 'set' zu definieren. Oder vielleicht habe ich einfach etwas falsch gemacht. Vielen Dank für die Hilfe!
Daniel Waltrip
Was ist MyClient ?
Kiquenet
@Kiquenet gibt es einen Link im Körper, zu hier: stackoverflow.com/questions/153451/…
Marc Gravell
136

Hier ist eine weitere Implementierung dieser Lösung:

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

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

BigJoe714
quelle
2
Ich verwende diesen Code, um zu überprüfen, ob eine Reihe von Bildern vorhanden ist, und er ist ziemlich langsam (einige Sekunden pro URL). Weiß jemand, ob dies ein Problem mit diesem Code ist oder nur eine Tatsache des Lebens, wenn er solche Anrufe tätigt?
Schmied
@ssmith Eine Möglichkeit, Ihren Code zu beschleunigen, besteht darin, die Prüfung in einer Parallel.Foreach-Schleife durchzuführen, wenn Sie dies noch nicht versucht haben. Es machte meine URL-Test-App viel schneller.
Jack Fairfield
3
Dieses Zeug wirft DisposedObject zurück (response.StatusCode == HttpStatusCode.OK); einwickeln mit
Lapenkov Vladimir
1
Es gibt ein Problem mit dem obigen Code. wenn Sie antworten.Close (); Dann können Sie nicht nach Antworten suchen. StatusCode löst beim Schließen eine Ausnahme aus.
Renascent
@ssmith irgendeine Methode viel schneller?
Kiquenet
36

Diese Lösungen sind ziemlich gut, aber sie vergessen, dass es möglicherweise andere Statuscodes als 200 OK gibt. Dies ist eine Lösung, die ich in Produktionsumgebungen zur Statusüberwachung und dergleichen verwendet habe.

Wenn auf der Zielseite eine URL-Umleitung oder eine andere Bedingung vorliegt, ist die Rückgabe mit dieser Methode wahr. Außerdem löst GetResponse () eine Ausnahme aus und daher erhalten Sie keinen StatusCode dafür. Sie müssen die Ausnahme abfangen und nach einem ProtocolError suchen.

Jeder 400- oder 500-Statuscode gibt false zurück. Alle anderen kehren wahr zurück. Dieser Code kann leicht an Ihre Anforderungen für bestimmte Statuscodes angepasst werden.

/// <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;
}
jsmith
quelle
1
Ich würde hinzufügen, dass einige Statuscodes im 3xx-Bereich tatsächlich dazu führen, dass ein Fehler ausgegeben wird, z. B. 304 Not Modified. In diesem Fall sollten Sie dies in Ihrem Catch-Block behandeln
RobV
3
Ich habe gerade ein Problem mit diesem Ansatz erlebt: Es HttpWebRequestgefällt mir nicht, wenn Sie .Close()das responseObjekt nicht verwenden, bevor Sie versuchen, etwas anderes herunterzuladen. Es hat Stunden gedauert, diesen zu finden!
Jbeldock
4
HttpWebResponseDas Objekt sollte in einem usingBlock eingeschlossen sein , da es implementiert, IDisposablewodurch auch das Schließen der Verbindung sichergestellt wird. Dies kann zu Problemen führen, mit denen @jbeldock konfrontiert ist.
Habib
2
Es wirft 404 Not Founds auf URLs, die in einem Browser gut funktionieren ...?
Michael Tranchida
@ MichaelTranchida-Webserver sind bekanntermaßen für 404 bekannt, wenn Sie eine Methode ausgeben, die nicht unterstützt wird. In Ihrem Fall Headwird diese Ressource möglicherweise nicht unterstützt Get. Es hätte stattdessen 405 werfen sollen.
Sriram Sakthivel
9

Wenn ich Ihre Frage richtig verstehe, können Sie eine kleine Methode wie diese verwenden, um die Ergebnisse Ihres URL-Tests zu erhalten:

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;

Sie können den obigen Code in eine Methode einbinden und damit eine Validierung durchführen. Ich hoffe, dies beantwortet die Frage, die Sie gestellt haben.

Kalendersoftware
quelle
1
Ja, vielleicht können Sie die Lösung verfeinern, indem Sie zwischen verschiedenen Fällen unterscheiden (TCP-Verbindungsfehler - Host verweigert Verbindung, 5xx - Es ist etwas Schwerwiegendes passiert, 404 - Ressource nicht gefunden usw.). Schauen Sie sich die Status-Eigenschaft von WebException an;)
David Taylor
Sehr guter Punkt David! Das würde uns ein detaillierteres Feedback geben, damit wir den Fehler klüger behandeln können.
Kalender-Software
1
Vielen Dank. Mein Punkt ist, dass diese Zwiebel mehrere Schichten hat, von denen jede einen Schraubenschlüssel in die Arbeit werfen kann (.Net Framework, DNS-Auflösung, TCP-Konnektivität, Zielwebserver, Zielanwendung usw.). Meiner Meinung nach sollte ein gutes Design in der Lage sein, zwischen den verschiedenen Fehlerbedingungen zu unterscheiden, um informatives Feedback und brauchbare Diagnosen zu liefern. Vergessen wir auch nicht, dass das HTTP aus einem bestimmten Grund Statuscodes hat;)
David Taylor
6

Versuchen Sie Folgendes (stellen Sie sicher, dass Sie System.Net verwenden):

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

Wenn die Funktion checkWebsite () aufgerufen wird, wird versucht, den Quellcode der übergebenen URL abzurufen. Wenn der Quellcode abgerufen wird, wird true zurückgegeben. Wenn nicht, wird false zurückgegeben.

Codebeispiel:

//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");
user6909992
quelle
3

Hier ist eine weitere Option

public static bool UrlIsValid(string url)
{
    bool br = false;
    try {
        IPHostEntry ipHost = Dns.Resolve(url);
        br = true;
    }
    catch (SocketException se) {
        br = false;
    }
    return br;
}
Zain Ali
quelle
3
Dies kann hilfreich sein, um zu überprüfen, ob ein Host vorhanden ist. Die Frage ist offensichtlich nicht besorgt darüber, ob der Host existiert oder nicht. Es geht um die Behandlung eines fehlerhaften HTTP-Pfads, da bekannt ist, dass der Host vorhanden und in Ordnung ist .
Binki
3

Diese Lösung scheint leicht zu folgen:

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 ;
}
abobjects.com
quelle
1
Vergessen Sie nicht, webResponse zu schließen, da sonst die Antwortzeit jedes Mal verlängert wird, wenn Sie Ihre Methode
aufrufen
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");`
}
Praveen Dasare
quelle
1
Bitte fügen Sie Ihrer Antwort eine Erklärung hinzu. Nur-Code-Antworten sind in der Regel verwirrend und für zukünftige Leser nicht hilfreich und können auf diese Weise zu Abstimmungen führen.
Jesse
2

Ich habe eine einfachere Möglichkeit, das Wetter zu bestimmen, für das eine URL gültig ist.

if (Uri.IsWellFormedUriString(uriString, UriKind.RelativeOrAbsolute))
{
   //...
}
tsingroo
quelle
4
Nein, diese Methode überprüft nicht, ob auf die URL wirklich zugegriffen werden kann. Es gibt sogar true zurück, wenn Uri.IsWellFormedUriString (" 192.168.1.421 ", ...) eine offensichtlich falsche URL verwendet
zhaorufei
2

Ich habe immer festgestellt, dass Ausnahmen viel langsamer behandelt werden.

Vielleicht würde ein weniger intensiver Weg zu einem besseren, schnelleren Ergebnis führen?

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

Dann benutze einfach:

IsValidUri(new Uri("http://www.google.com/censorship_algorithm"));
rostiger Nagel
quelle
1

Webserver antworten mit einem HTTP-Statuscode, der das Ergebnis der Anforderung angibt, z. B. 200 (manchmal 202) bedeutet Erfolg, 404 - nicht gefunden usw. (siehe hier ). Angenommen, der Teil der Serveradresse in der URL ist korrekt und Sie erhalten kein Socket-Timeout. Die Ausnahme teilt Ihnen höchstwahrscheinlich mit, dass der HTTP-Statuscode nicht 200 war. Ich würde empfehlen, die Klasse der Ausnahme zu überprüfen und festzustellen, ob die Ausnahme vorliegt den HTTP-Statuscode.

IIRC - Der betreffende Aufruf löst eine WebException oder einen Nachkommen aus. Überprüfen Sie den Klassennamen, um festzustellen, welcher, und schließen Sie den Aufruf in einen try-Block ein, um die Bedingung abzufangen.

David Taylor
quelle
2
Eigentlich bedeutet alles im Bereich von 200
299
Marc, du bist absolut richtig. Ich habe es absichtlich vermieden, in das Konzept der "Fehlerklasse" einzusteigen (z. B. 5xx, 4xx, 3xx, 2xx usw.), da dies eine ganz andere Dose Würmer öffnet. Selbst die Handhabung der Standardcodes (200, 302, 404, 500 usw.) ist viel besser, als die Codes vollständig zu ignorieren.
David Taylor
1

In Anlehnung an die bereits gegebenen Beispiele würde ich sagen, dass es empfehlenswert ist, die Antwort auch in eine Verwendung wie diese zu verpacken

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