如果需要,将方案添加到URL


70

要从字符串创建Uri,您可以执行以下操作:

Uri u = new Uri("example.com");

但是问题是,如果字符串(如上面的字符串)不包含协议,您将得到一个异常:“ Invalid URI: The format of the URI could not be determined.

为避免异常,您应确保该字符串包含协议,如下所示:

Uri u = new Uri("http://example.com");

但是,如果您将url作为输入,如果缺少协议,如何添加协议呢?
我的意思是除了一些IndexOf / Substring操作之外?

优雅又快速的东西?


IndexOf应该足够快。
Scrum Meister

10
小点;“方案” ...而不是“协议”
马克·格雷夫

Answers:


133

您还可以使用UriBuilder

public static Uri GetUri(this string s)
{
    return new UriBuilder(s).Uri;
}

来自MSDN的评论:

此构造函数使用uri中指定的Fragment,Host,Path,Port,Query,Scheme和Uri属性初始化UriBuilder类的新实例。

如果uri没有指定方案,则该方案默认为“ http:”。


3
这表示,当您尝试无协议呼叫的网址(例如“ //domain.com”)时,无法解析主机名
John

18
谨慎使用:带有类似端口的输入将stackoverflow.com:80被正确解析,但将被解释为Scheme: stackoverflow.comPath: 80Port: -1。并非完全符合预期...
linac

如果缺少该方案,则可以使用。如果主机名也丢失(例如/foo/bar),则会抛出“无效的URI:无法解析主机名”。
Georg Patscheider

7

如果只想添加方案而不验证URL,最快/最简单的方法是使用字符串查找,例如:

string url = "mydomain.com";
if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) url = "http://" + url;

更好的方法是Uri使用以下TryCreate方法来验证URL :

string url = "mydomain.com";
Uri uri;
if ((Uri.TryCreate(url, UriKind.Absolute, out uri) || Uri.TryCreate("http://" + url, UriKind.Absolute, out uri)) &&
    (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
{
    // Use validated URI here
}

正如@JanDavidNarkiewicz在评论中指出的那样,Scheme当指定了没有方案的端口(例如)时,必须验证,以防止无效的方案mydomain.com:80


1
由于存在一个非常细微的问题,该方法将不起作用:带有端口(“ mydomain.com:8080”)的网址在传递给TryCreate时将返回true。Uri的方案是mydomain.com。认为Uri班有一个bug,但高于薪水等级。
Jan David Narkiewicz

@JanDavidNarkiewicz您是正确的,这可能是因为mailto:并且tel:也是有效的方案,并且端口分隔符被视为方案分隔符。我已经更新了代码以防止这种情况!
罗纳德

@ S.Serpooshan仅当您确定URL支持HTTPS时...所以最安全的方法是默认为HTTP(就像浏览器,编辑器等一样)!
罗纳德

4

我的解决方案是使用无需protocall的URL,以确保它们具有protocal是正则表达式:

Regex.Replace(s, @"^\/\/", "http://");

这正则表达式只是如果有一个双斜线测试//在字符串的开始,而不是例如对于工作www.stackoverflow.com
S.Serpooshan

2

有趣的是,虽然UriUriBuilder完全撕裂任何URL,而不方案,WebProxy确实是正确的。

因此,只需致电:

new WebProxy(proxy.ProxyServer).Address

0

在某些特定情况下,有一定的余量可以输入类似localhost:8800或类似的内容。这意味着我们需要解析它。我们构建了一个更精细的ParseUri方法,该方法非常松散地分离了指定URI的可能性,但也抓住了人们指定非标准方案的时代(还有IP长度表示法的主机,因为有时人们会这样做)

与UriBuilder一样,如果未指定,则默认使用http方案。如果指定了基本身份验证,并且密码仅包含数字,它将出现问题。(随时修复该社区)

        private static Uri ParseUri(string uri)
        {

            if (uri.StartsWith("//"))
                return new Uri("http:" + uri);
            if (uri.StartsWith("://"))
                return new Uri("http" + uri);

            var m = System.Text.RegularExpressions.Regex.Match(uri, @"^([^\/]+):(\d+)(\/*)", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline);
            if (m.Success)
            {
                var port = int.Parse(m.Groups[2].Value);
                if (port <= 65535) //part2 is a port (65535 highest port number)
                    return new Uri("http://" + uri);
                else if (port >= 16777217) //part2 is an ip long (16777217 first ip in long notation)
                    return new UriBuilder(uri).Uri;
                else
                    throw new ArgumentOutOfRangeException("Invalid port or ip long, technically could be local network hostname, but someone needs to be hit on the head for that one");
            }
            else
                return new Uri(uri);
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.