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*
}
消息框显示的地址如
mailto:网站管理员[@] somehost?网站管理员
这显然是格式错误,但我没有得到的是为什么它没有被第一个 catch块捕获?
MSDN says它只能抛出InvalidOperationException
。这很成问题,因为这意味着我的应用程序可以随时爆炸!
[[剪断]]
答案 0 :(得分:8)
首先,我想说使用Exception来检查有效性并不是一个好主意,因为你可以使用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:网站管理员[@] somehost?网站管理员
URI为Uniform Resource Identifier,因此其basic syntax
{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;
阅读有关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);
以“错误方案”结束。也许我不正确理解你?
将href更改为:
时 const string href = "http: webmaster [ @ ] somehost ?webmaster";
它正确传递,自动转义为uri:
http://localhost/%20webmaster%20%5B%20@%20%5D%20somehost%20?webmaster
也可以使用所有uri的组件。
我在第一部分中尝试解释的主要问题是:
在我看来,您错误地将任何统一资源标识符视为基于http的网址,但这是错误的。
mailto:webmaster@somehost.tst
或gopher://gopher.hprc.utoronto.ca/
或myreshandler://something@somewhere
也是有效的URI,可以成功解析。看看Official IANA-registered schemes
所以
Uri构造函数行为是预期且正确的。
它尝试验证known schemes的传入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 scheme generic syntax)。
基本Uri.TryCreate()
和方案检查足以获得可以传递给.NET HttpWebRequest的链接。你真的不需要检查它们是否格式正确或没有。如果链接不好(格式不正确或不存在),则在尝试请求时只会得到相应的HttpError。
至于你的例子:
它通过我的支票并变为:
您无需检查是否格式正确或没有。只需进行基本检查并尝试请求。希望它有所帮助。
此外,字符串mailto:webmaster [@] somehost?网站管理员格式不正确。我的字面意思是,那个字符串,愚蠢的[]和其中的一切
此字符串格式错误意思不是格式正确(因为包含排除在RFC 2396之后的字符)但它仍然可以被视为由于URI方案的一致性通用语法而有效(还要检查在使用http :)创建时如何转义。
答案 1 :(得分:1)
如果深入研究Uri.Host
属性(真正的深层),它最终可以调用静态函数GetException
,它会针对无效URI的不同条件返回UriFormatException
个对象。打印出您获得的完整UriFormatException
,并将其与Uri.GetException
生成的{{1}}进行比较。您可能会从中获得更多详细信息。
答案 2 :(得分: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);
}