uri.Host如何抛出UriFormatException?

mpe*_*pen 0 .net c# url uri exception

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*
}
Run Code Online (Sandbox Code Playgroud)

消息框显示如下地址

mailto:webmaster [@] somehost?网站管理员

这显然是畸形的,但我没有得到的是为什么它没有被第一个捕获块捕获?

MSDN说它只能抛出一个InvalidOperationException.这很成问题,因为这意味着我的应用程序可以随时爆炸!

[[剪断]]

Nic*_*nko 8

首先,我想说使用Exception来检查有效性并不是一个好主意,因为你可以使用Uri.TryCreate方法.因此,您可以重写代码,而不是依赖于可以抛出和捕获的异常.

所以最好改变你的

Uri uri;
try
{
    uri = new Uri(item.Value.Uri, href);
}
catch(UriFormatException)
{
    continue;
}
Run Code Online (Sandbox Code Playgroud)

Uri uri;
if (!Uri.TryCreate(item.Value.Uri, href, out uri)) continue;
Run Code Online (Sandbox Code Playgroud)

但无论如何,这还不是全面检查.

至于你的问题,答案相对简单.假设畸形,你错了:

mailto:webmaster [@] somehost?网站管理员

URI是统一资源标识符,因此它的基本语法

{scheme name}:{hierarchical part} [?{query}] [#{fragment}]

显然对你的输入有效.使用"mailto:"方案结束资源的URI.

当您尝试访问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;
Run Code Online (Sandbox Code Playgroud)

阅读有关UriParser的一些信息


这里根据@Mark评论进行更新.

当我试图获得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);
Run Code Online (Sandbox Code Playgroud)

它以"错误的方案"结束.也许我不正确理解你?

当您将href更改为:

        const string href = "http: webmaster [ @ ] somehost ?webmaster";
Run Code Online (Sandbox Code Playgroud)

它正确传递,自动转义为uri:

HTTP://本地主机/%20webmaster%20%5B%20 @%20%5D%20somehost 20%站长

也可以使用所有uri的组件.

我试着在第一部分中解释的主要问题如下:

在我看来,你错误地将任何统一资源标识符视为基于http的网址,但这是错误的.mailto:webmaster@somehost.tst或者gopher://gopher.hprc.utoronto.ca/myreshandler://something@somewhere也有效的URI可以被成功地解析.查看IANA官方注册的计划

所以

Uri构造函数行为是预期和正确的.

它尝试验证已知方案的传入URI :

  • UriSchemeFile- 指定URI是指向文件的指针.
  • UriSchemeFtp- 指定通过文件传输协议(FTP)访问URI.
  • UriSchemeGopher- 指定通过Gopher协议访问URI.
  • UriSchemeHttp- 指定通过超文本传输​​协议(HTTP)访问URI
  • UriSchemeHttps- 指定通过安全超文本传输​​协议(HTTPS)访问URI.
  • UriSchemeMailto- 指定URI是电子邮件地址,并通过简单网络邮件协议(SNMP)访问.
  • UriSchemeNews- 指定URI是Internet新闻组,并通过网络新闻传输协议(NNTP)访问.
  • UriSchemeNntp- 指定URI是Internet新闻组,并通过网络新闻传输协议(NNTP)访问

当方案未知时使用基本URI解析器(请参阅URI方案通用语法).


基本上Uri.TryCreate()和方案检查足以获得可以传递给.NET HttpWebRequest的链接,例如.你真的不需要检查它们是否结构良好或没有.如果链接不好(格式不正确或不存在),则在尝试请求时只会得到相应的HttpError.

至于你的例子:

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

它通过我的检查,成为:

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

你不需要检查它是否格式正确或没有.只需进行基本检查并尝试请求.希望能帮助到你.


此外,字符串mailto:webmaster [@] somehost?网站管理员格式不正确.我的字面意思是,那个字符串,愚蠢的[]和其中的一切

这个字符串格式错误,意思不是很好(因为根据RFC 2396包含排除的字符),但由于URI方案的一致性通用语法,它仍然可以被认为是有效的(检查它是如何在使用http :)创建时转义的.