2010-10-20 23 views
0
foreach (var node in root.Find("a[href]")) 
{ 
    var href = node.Attributes["href"].Value; 
    Uri uri; 
    try 
    { 
     uri = new Uri(item.Value.Uri, href); 
    } 
    catch(UriFormatException) 
    { 
     continue; 
    } 
    // *snip* 
    try 
    { 
     if (_imageHosts.IsMatch(uri.Host)) // <--- problematic line 
      priority--; 
    }catch(UriFormatException) 
    { 
     MessageBox.Show(uri.OriginalString); // <--- gets displayed when I expected it wouldn't 
     continue; 
    } 
    // *snip* 
} 

消息框顯示了類似uri.Host如何拋出UriFormatException異常?

郵寄地址地址:網站管理員[@],某網站管理員

這顯然是畸形的,但我不明白是爲什麼呢?是不是被第一個 catch catch?它只能拋出一個InvalidOperationException。這是相當有問題的,因爲這意味着我的應用程序可以隨時爆炸!

[剪斷]

+0

Uri.IsWellFormedUriString檢查根據RFC2396 URI一致性 - 統一資源標識符(URI):通用語法http://bit.ly/b83qyw,如2.4.3規定。排除的US-ASCII字符。空間必須在URI中轉義。我也會更新我的答案。 – 2010-10-20 18:02:01

回答

8

首先,我想說它沒有這麼好的主意,因爲您可以使用Uri.TryCreate方法來使用異常來檢查有效性。所以你可以重寫你的代碼,而不是依靠哪個異常可以被拋出和捕獲。

因此,更好地改變你的

Uri uri; 
try 
{ 
    uri = new Uri(item.Value.Uri, href); 
} 
catch(UriFormatException) 
{ 
    continue; 
} 

Uri uri; 
if (!Uri.TryCreate(item.Value.Uri, href, out uri)) continue; 

但是,這並不全面檢查反正。

至於你的問題,答案相對簡單。你錯了假設畸形:

的mailto:網站管理員[@],某網站管理員

URI是Uniform Resource Identifier所以其basic syntax

{方案名稱}:{層次一部分}? {query}] [#{fragment}]

顯然對您的輸入有效。您以資源的URI與「mailto:」方案結束。

當您嘗試訪問Host屬性時,您認爲資源是Http,但默認情況下使用的「mailto」-scheme解析器無法解析主機組件的原始字符串,從而引發異常。

所以寫支票正確,您必須修改您的代碼位:

Uri uri; 
if (!Uri.TryCreate(item.Value.Uri, href, out uri)) continue; 

if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) continue; 

閱讀UriParser


這裏更新基於@馬克評論的一些信息。

我敢肯定,當我試圖獲得AbsoluteUri屬性時,它會拋出異常。爲什麼會失敗?

您不能通過Scheme檢查,因爲它會是「mailto」。所以這裏快速測試:

 var baseUri = new Uri("http://localhost"); 
     const string href = "mailto: webmaster [ @ ] somehost ?webmaster"; 

     Uri uri; 
     if (!Uri.TryCreate(baseUri,href, out uri)) 
     { 
      Console.WriteLine("Can't create"); 
      return; 
     } 

     if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) 
     { 
      Console.WriteLine("Wrong scheme"); 
      return; 
     } 

     Console.WriteLine("Testing uri: {0}", uri); 

它以「錯誤的方案」結束。也許我不正確地理解你?

當您更改HREF到:

 const string href = "http: webmaster [ @ ] somehost ?webmaster"; 

它正確傳遞,自動轉義的URI:

http://localhost/%20webmaster%20%5B%[email protected]%20%5D%20somehost%20?webmaster

也都URI的組成部分將提供給你。

主要的問題我儘量在第一部分如下解釋:

在我看來,你會錯誤地將任何統一資源標識符爲HTTP(S)基於URL,但這是錯誤的。 mailto:[email protected]gopher://gopher.hprc.utoronto.ca/myreshandler://[email protected]也是可以被成功解析的有效URI。採取Official IANA-registered schemes

所以

URI構造行爲是正常和正確的看看。

它嘗試驗證傳入的URI爲known schemes

  • UriSchemeFile - 指定URI是一個指針到一個文件。
  • UriSchemeFtp - 指定通過文件傳輸協議(FTP)訪問URI。
  • UriSchemeGopher - 指定通過Gopher協議訪問URI。
  • UriSchemeHttp - 指定URI是通過超文本傳輸​​協議(HTTP)
  • UriSchemeHttps訪問 - 指定URI通過安全超文本傳輸​​協議(HTTPS)訪問。
  • UriSchemeMailto - 指定URI是電子郵件地址並通過簡單網絡郵件協議(SNMP)訪問。
  • UriSchemeNews - 指定URI是Internet新聞組並通過網絡新聞傳輸協議(NNTP)訪問。
  • UriSchemeNntp - 指定URI是Internet新聞組,並通過在方案是不知道

基本URI解析器使用網絡新聞傳輸協議(NNTP)進行訪問(詳見URI scheme generic syntax)。


Basicly Uri.TryCreate()和方案的檢查足以讓可以傳遞到.NET的HttpWebRequest例如鏈接。你並不需要檢查它們是否合格或不合格。如果鏈接不好(不是格式正確或不存在),當你嘗試請求它們時,你會得到相應的HttpError。

至於你的例子:

http://www.google.com/search?q=cheesy

它通過我的支票,併成爲:

http://www.google.com/search?q=cheesy%20poof

你並不需要檢查它是格式良好還是沒有。只要做基本檢查並嘗試請求。希望能幫助到你。


此外,該字符串的mailto:?站長[@],某網站管理員格式錯誤。我字面上的意思是,該字符串,與笨[s和一切都在它

此字符串是畸形通過意義不合式(因爲含有根據RFC 2396排除的字符),但它仍然可以由於URI方案的一致性通用語法(請檢查使用http創建時如何逃脫),因此可以認爲它是有效的

+0

我很確定它在我試圖獲得'AbsoluteUri'屬性時拋出一個異常。爲什麼會失敗? – mpen 2010-10-20 16:56:40

+0

此外,字符串'mailto:webmaster [@] somehost?webmaster' * *格式不正確。我的意思是,字符串,愚蠢的[]和其中的一切。 – mpen 2010-10-20 17:03:33

+0

我想mailtos會有一個AbsoluteUri ...我想不是。我只是檢查你的建議,然後! Uri的基礎是「WebClient.DownloadData」,我基本上想要允許任何可以處理的東西......「默認情況下,.NET Framework支持以http :, https :, ftp :,和file開頭的URI:方案標識符「。 - 我想我也應該包括那些。 – mpen 2010-10-20 20:00:48

1

如果深挖到Uri.Host屬性(實深),它最終可以調用靜態函數GetException返回無效的URI的不同條件UriFormatException對象。打印出您正在獲取的完整UriFormatException,並將其與Uri.GetException生成的結果進行比較。你可能會從中得到更多的細節。

1

基於尼克的回答是:

private static readonly string[] SupportedSchmes = { Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeFtp, Uri.UriSchemeFile }; 

private static bool TryCreateUri(string uriString, out Uri result) 
{ 
    return Uri.TryCreate(uriString, UriKind.Absolute, out result) && SupportedSchmes.Contains(result.Scheme); 
} 

private static bool TryCreateUri(Uri baseAddress, string relativeAddress, out Uri result) 
{ 
    return Uri.TryCreate(baseAddress, relativeAddress, out result) && SupportedSchmes.Contains(result.Scheme); 
}