C # Làm cách nào để kiểm tra xem một URL có tồn tại / hợp lệ hay không?


117

Tôi đang tạo một chương trình đơn giản bằng visual c # 2005 để tra cứu một ký hiệu chứng khoán trên Yahoo! Tài chính, tải xuống dữ liệu lịch sử, sau đó lập biểu đồ lịch sử giá cho biểu tượng mã được chỉ định.

Tôi biết URL chính xác mà tôi cần để lấy dữ liệu và nếu người dùng nhập một biểu tượng mã cổ phiếu hiện có (hoặc ít nhất một biểu tượng có dữ liệu trên Yahoo! Finance) thì nó hoạt động hoàn toàn tốt. Tuy nhiên, tôi gặp lỗi thời gian chạy nếu người dùng tạo biểu tượng mã cổ phiếu vì chương trình cố gắng lấy dữ liệu từ một trang web không tồn tại.

Tôi đang sử dụng lớp WebClient và sử dụng chức năng DownloadString. Tôi đã xem qua tất cả các hàm thành viên khác của lớp WebClient, nhưng không thấy bất kỳ thứ gì tôi có thể sử dụng để kiểm tra URL.

Tôi có thể làm cái này như thế nào?


1
được cập nhật để hiển thị mức sử dụng C # 2.0 (VS2005)
Marc Gravell

Câu trả lời:


110

Bạn có thể đưa ra yêu cầu "HEAD" thay vì "GET"?

(sửa) - lol! Có vẻ như tôi đã làm điều này trước đây !; đã thay đổi thành wiki để tránh bị cáo buộc thu thập lại. Vì vậy, để kiểm tra một URL mà không mất phí tải xuống nội dung:

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

Bạn sẽ try/ catchxung quanh DownloadStringđể kiểm tra lỗi; không có lỗi? Nó có tồn tại...


Với 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 - Không chắc liệu điều đó có thực sự giải quyết được vấn đề hay không (ngoại trừ phía ứng dụng khách có hành vi khác) vì bạn chỉ đơn giản là thay đổi phương thức HTTP. Phản hồi từ máy chủ sẽ phụ thuộc nhiều vào cách mã hóa logic và có thể không hoạt động tốt đối với một dịch vụ động như giá cổ phiếu. Đối với tài nguyên tĩnh (ví dụ: hình ảnh, tệp, v.v.) HEAD thường hoạt động như được quảng cáo vì nó được đưa vào máy chủ. Nhiều lập trình viên không HEAD rõ ràng yêu cầu vì tiêu điểm thường là POST và GET. YMMV
David Taylor

Xin lỗi vì đã mất quá nhiều thời gian để chọn một câu trả lời ... Tôi đã bị xáo trộn với trường học và công việc và đại loại là quên mất bài đăng này. Như một chú thích phụ, tôi không thể làm cho giải pháp của bạn hoạt động vì tôi đang sử dụng Visual Studio 2005 không có kiểu 'var'. Tôi đã không làm việc với dự án này trong nhiều tháng, nhưng có cách khắc phục đơn giản nào cho thực tế đó không? Ngoài ra, khi tôi cố gắng triển khai giải pháp của bạn, tôi nhớ rằng tôi đã rất tức giận vì đã cố gắng xác định thuộc tính HeadOnly mà không có mã nào trong định nghĩa 'get' và 'set'. Hoặc có thể tôi đã làm sai điều gì đó. Cảm ơn sự giúp đỡ của bạn!
Daniel Waltrip

MyClient là gì?
Kiquenet

@Kiquenet có một liên kết trong nội dung, tới đây: stackoverflow.com/questions/153451/…
Marc Gravell

136

Đây là một triển khai khác của giải pháp này:

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

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


2
Tôi đang sử dụng mã này để kiểm tra xem liệu một loạt hình ảnh có tồn tại hay không và nó khá chậm (vài giây cho mỗi URL). Có ai đó biết liệu đây có phải là vấn đề với mã này hay chỉ là một thực tế của cuộc sống khi thực hiện những cuộc gọi kiểu này?
ssmith

@ssmith Một cách bạn có thể tăng tốc mã của mình là kiểm tra trong vòng lặp Parallel.Foreach nếu bạn chưa thử. Nó làm cho ứng dụng kiểm tra url của tôi nhanh hơn NHIỀU.
Jack Fairfield

3
Công cụ này sẽ ném lại DisposedObject (response.StatusCode == HttpStatusCode.OK); quấn vào sử dụng
Lapenkov Vladimir

1
Có một vấn đề với mã trên. nếu bạn thực hiện response.Close (); thì bạn không thể kiểm tra phản hồi. Mã trạng thái khi đóng, nó sẽ tạo ra một ngoại lệ.
Renascent

@ssmith có phương pháp nào nhanh hơn nhiều không?
Kiquenet

36

Các giải pháp này khá tốt, nhưng họ đang quên rằng có thể có các mã trạng thái khác hơn 200 OK. Đây là một giải pháp mà tôi đã sử dụng trên các môi trường sản xuất để theo dõi trạng thái và như vậy.

Nếu có một chuyển hướng url hoặc một số điều kiện khác trên trang đích, kết quả trả về sẽ là true khi sử dụng phương pháp này. Ngoài ra, GetResponse () sẽ ném ra một ngoại lệ và do đó bạn sẽ không nhận được Mã trạng thái cho nó. Bạn cần bẫy ngoại lệ và kiểm tra lỗi ProtocolError.

Bất kỳ mã trạng thái 400 hoặc 500 nào sẽ trả về false. Tất cả những người khác trả về true. Mã này dễ dàng được sửa đổi để phù hợp với nhu cầu của bạn đối với các mã trạng thái cụ thể.

/// <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
Tôi muốn nói thêm rằng một số mã trạng thái trong khoảng 3xx thực sự sẽ gây ra một lỗi được ném ví dụ như 304 Not Modified trong trường hợp này bạn nên xử lý rằng trong khối catch của bạn
RobV

3
Bạn vừa gặp phải vấn đề khó hiểu với cách tiếp cận này: HttpWebRequestkhông thích nó nếu bạn không phải .Close()responseđối tượng trước khi bạn cố gắng tải xuống bất kỳ thứ gì khác. Đã mất hàng giờ để tìm ra cái đó!
jbeldock

4
HttpWebResponseđối tượng nên được bao bọc trong usingkhối vì nó thực hiện IDisposablecũng sẽ đảm bảo đóng kết nối. Điều này có thể gây ra sự cố như @jbeldock, đã gặp phải.
Habib

2
Nó đang ném 404 Not Founds vào các url hoạt động tốt trong trình duyệt ...?
Michael Tranchida

@MichaelTranchida Máy chủ web nổi tiếng với 404 khi bạn phát hành một phương pháp không được hỗ trợ. Trong trường hợp của bạn có Headthể không được hỗ trợ trên tài nguyên đó mặc dù Getcó thể được. Thay vào đó, nó nên ném 405.
Sriram Sakthivel,

9

Nếu tôi hiểu đúng câu hỏi của bạn, bạn có thể sử dụng một phương pháp nhỏ như sau để cung cấp cho bạn kết quả kiểm tra URL của bạn:

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;

Bạn có thể bọc đoạn mã trên trong một phương thức và sử dụng nó để thực hiện xác thực. Tôi hy vọng điều này trả lời câu hỏi bạn đang hỏi.


1
Có, có lẽ bạn có thể tinh chỉnh giải pháp bằng cách phân biệt giữa các trường hợp khác nhau (lỗi kết nối TCP - máy chủ từ chối kết nối, 5xx - Đã xảy ra sự cố nghiêm trọng, 404 - Không tìm thấy tài nguyên, v.v.). Hãy xem thuộc tính Trạng thái của WebException;)
David Taylor

Rất tốt điểm David! Điều đó sẽ cung cấp cho chúng tôi phản hồi chi tiết hơn để chúng tôi có thể xử lý lỗi một cách sắc sảo hơn.
Phần mềm Lịch

1
Cảm ơn. Quan điểm của tôi là có một số lớp đối với củ hành này, mỗi lớp có thể ném một chìa khóa vào hoạt động (.Net Framework, DNS Resolution, TCP Connectivity, target Web Server, target application, v.v.). IMHO một thiết kế tốt phải có khả năng phân biệt giữa các điều kiện hư hỏng khác nhau để cung cấp phản hồi thông tin và chẩn đoán có thể sử dụng được. Cũng đừng quên HTTP có mã trạng thái là có lý do;)
David Taylor,

6

Hãy thử điều này (Đảm bảo bạn sử dụng System.Net):

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

Khi hàm checkWebsite () được gọi, nó sẽ cố gắng lấy mã nguồn của URL được chuyển vào nó. Nếu nó nhận được mã nguồn, nó sẽ trả về true. Nếu không, nó trả về false.

Ví dụ về mã:

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

Đây là một tùy chọn khác

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
Điều đó có thể hữu ích để kiểm tra xem máy chủ có tồn tại hay không. Câu hỏi rõ ràng là không phải lo lắng về việc vật chủ có tồn tại hay không. Nó liên quan đến việc xử lý một đường dẫn HTTP không hợp lệ vì máy chủ được biết là tồn tại và ổn .
binki

3

Giải pháp này có vẻ dễ làm theo:

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
đừng quên đóng webResponse, nếu không thời gian phản hồi sẽ tăng lên mỗi khi bạn gọi phương thức của mình
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
Vui lòng thêm một số giải thích cho câu trả lời của bạn. Các câu trả lời chỉ có mã có xu hướng gây nhầm lẫn và không hữu ích cho người đọc trong tương lai và có thể thu hút sự phản đối theo cách đó.
Jesse

2

tôi có một cách đơn giản hơn để xác định thời tiết một url hợp lệ.

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

4
Không, phương pháp này không kiểm tra xem url có thực sự có thể truy cập được hay không. Nó thậm chí còn trả về true khi Uri.IsWellFormedUriString ( " 192.168.1.421 ", ...), trong đó sử dụng một địa chỉ rõ ràng không chính xác
zhaorufei

2

Tôi luôn thấy rằng các Ngoại lệ chậm hơn nhiều để được xử lý.

Có lẽ một cách ít chuyên sâu hơn bạn sẽ tạo ra một kết quả tốt hơn, nhanh hơn?

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

Sau đó, chỉ cần sử dụng:

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

1

Máy chủ web phản hồi với mã trạng thái HTTP cho biết kết quả của yêu cầu, ví dụ 200 (đôi khi là 202) có nghĩa là thành công, 404 - không tìm thấy, v.v. (xem tại đây ). Giả sử phần địa chỉ máy chủ của URL là chính xác và bạn không nhận được thời gian chờ socket, thì ngoại lệ rất có thể cho bạn biết mã trạng thái HTTP khác 200. Tôi khuyên bạn nên kiểm tra lớp của ngoại lệ và xem liệu ngoại lệ có mang mã trạng thái HTTP.

IIRC - Cuộc gọi được đề cập ném một WebException hoặc một phần tử con. Kiểm tra tên lớp để xem tên lớp nào và gói lệnh gọi trong một khối thử để bẫy điều kiện.


2
Trên thực tế, bất kỳ thứ gì trong phạm vi 200-299 đều có nghĩa là thành công, IIRC
Marc Gravell

Marc, bạn hoàn toàn chính xác. Tôi cố tình tránh đi vào khái niệm "lớp lỗi" (ví dụ: 5xx, 4xx, 3xx, 2xx, v.v.) vì điều đó mở ra toàn bộ các hộp sâu khác. Ngay cả việc xử lý các mã tiêu chuẩn (200, 302, 404, 500, v.v.) tốt hơn nhiều so với việc bỏ qua các mã hoàn toàn.
David Taylor,

1

Tiếp theo từ các ví dụ đã được đưa ra, tôi muốn nói, cách tốt nhất là bạn cũng nên gói phản hồi bằng cách sử dụng như thế này

    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;
        }
   }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.