System.Uri类 - 获取Url的各种属性,文件名,参数,域名,端口等等

本文详细介绍了System.Uri类的属性和方法,包括如何处理URI地址信息,例如从相对URI地址转换为绝对URI地址,以及如何获取URI的各部分信息。

 System.Uri类用于处理Uri地址信息,常用到它的地方有,相对Uri地址转绝对Uri地址,获取Uri的某部分信息等等,可以说是一个非常有用的类。

一、属性

AbsolutePath   获取 URI 的绝对路径。 
AbsoluteUri     获取绝对 URI。 
Authority      获取服务器的域名系统 (DNS) 主机名或 IP 地址和端口号。 
DnsSafeHost   获得可安全用于 DNS 解析的未转义主机名。 
Fragment     获取转义 URI 片段。 
Host        获取此实例的主机部分。 
HostNameType  获取 URI 中指定的主机名的类型。 
IsAbsoluteUri   获取一个值,该值指示 Uri 实例是否为绝对 URI。 
IsDefaultPort   获取一个值,该值指示 URI 的端口值是否为此方案的默认值。 
IsFile       获取一个值,该值指示指定的 Uri 是否为文件 URI。 
IsLoopback     获取一个值,该值指示指定的 Uri 是否引用了本地主机。 
IsUnc       获取一个值,该值指示指定的 Uri 是否为统一命名约定 (UNC) 路径。 
LocalPath     获取文件名的本地操作系统表示形式。 
OriginalString   获取传递给 Uri 构造函数的原始 URI 字符串。 
PathAndQuery   获取用问号 (?) 分隔的 AbsolutePath 和 Query 属性。 
Port         获取此 URI 的端口号。 
Query       获取指定 URI 中包括的任何查询信息。 
Scheme      获取此 URI 的方案名称。 
Segments     获取包含构成指定 URI 的路径段的数组。 
UserEscaped     指示 URI 字符串在创建 Uri 实例之前已被完全转义。 
UserInfo       获取用户名、密码或其他与指定 URI 关联的特定于用户的信息。

复制代码
class Program
    {
        static void Main(string[] args)
        {
            Uri uri = new Uri("http://www.baidu.com:80/2013/123.html?id=1");
            
            Console.WriteLine(uri.AbsolutePath);    //输出 /2013/123.html
            Console.WriteLine(uri.AbsoluteUri);     //输出 http://www.baidu.com/2013/123.html?id=1
            Console.WriteLine(uri.Authority);       //输出 www.baidu.com
            Console.WriteLine(uri.DnsSafeHost);     //输出 www.baidu.com
            Console.WriteLine(uri.Fragment);        //输出 
            Console.WriteLine(uri.Host);            //输出 www.baidu.com
            Console.WriteLine(uri.IsAbsoluteUri);   //输出 True
            Console.WriteLine(uri.IsDefaultPort);   //输出 True
            Console.WriteLine(uri.IsFile);          //输出 False

            Uri uri1 = new Uri(@"D:\test\test.txt");
            Console.WriteLine(uri1.IsFile);          //输出 True

            Console.WriteLine(uri.IsLoopback);      //输出 False
            Console.WriteLine(uri1.IsLoopback);     //输出 True

            Console.WriteLine(uri.IsUnc);           //输出 False
            Console.WriteLine(uri.LocalPath);       //输出 /2013/123.html
            Console.WriteLine(uri.OriginalString);  //输出 http://www.baidu.com:80/2013/123.html
            Console.WriteLine(uri.PathAndQuery);    //输出 /2013/123.html?id=1
            Console.WriteLine(uri.Port);            //输出 80
            Console.WriteLine(uri.Query);           //输出 ?id=1
            Console.WriteLine(uri.Scheme);          //输出 http
            string[] strArr = uri.Segments;
            foreach (string str in strArr)
            {
                Console.WriteLine(str);     //输出 /   2013/      123.html
            }

            Console.WriteLine(uri.UserEscaped);     //输出 False;
            Console.WriteLine(uri.UserInfo);        //输出 

            Console.ReadKey();
        }
    }
复制代码

 二、方法

CheckHostName     确定指定的主机名是否为有效的 DNS 名称。 
CheckSchemeName    确定指定的方案名是否有效。 
Compare          使用指定的比较规则比较两个 URI 的指定部分。 
EscapeDataString    将字符串转换为它的转义表示形式。 
EscapeUriString     将 URI 字符串转换为它的转义表示形式。 
FromHex          获取十六进制数字的十进制值。 
GetComponents     使用特殊字符的指定转义,获取当前实例的指定部分。 
GetLeftPart        获取 Uri 实例的指定部分。 
GetObjectData       返回序列化当前实例所需的数据。 
HexEscape         将指定的字符转换它的等效十六进制字符。 
HexUnescape       将字符的指定十六进制表示形式转换为字符。 
IsBaseOf         确定当前的 Uri 实例是否为指定 Uri 实例的基。 
IsHexDigit        确定指定的字符是否为有效的十六进制数字。 
IsHexEncoding       确定字符串中的一个字符是否为十六进制编码。 
IsWellFormedOriginalString   指示用于构造此 Uri 的字符串是否格式良好,以及它是否不需要进一步转义。 
IsWellFormedUriString   通过尝试用字符串构造一个 URI 来指示字符串是否为格式良好的,并确保字符串不需要进一步转义。 
MakeRelativeUri      确定两个 Uri 实例之间的差异。 
TryCreate         已重载。 创建一个新的 Uri。在无法创建 Uri 时不引发异常。 
UnescapeDataString   将字符串转换为它的非转义表示形式。

复制代码
class Program
    {
        static void Main(string[] args)
        {
        

            Uri uri = new Uri("http://www.baidu.com:80/2013/123.html?id=1");
            UriHostNameType unt = Uri.CheckHostName("http://www.baidu.com");
            Console.WriteLine(unt.ToString());   //输出Unknown    UriHostNameType 是一个枚举,定义主机名类型

            Console.WriteLine(Uri.CheckSchemeName("http://www.baidu.com")); //输出 False
            Console.WriteLine(Uri.CheckSchemeName("http"));     //输出 True
            Console.WriteLine(Uri.CheckSchemeName("https"));    //输出 True
            //Uri uri1 = new Uri("http://www.baidu.com");
            //Uri.Compare(uri,uri1);

            //Uri.EscapeDataString对冒号(:)、斜杠(/)、空格、中文、井号(#)都进行了编码,可对参数编码
            Console.WriteLine(Uri.EscapeDataString("http://www.baidu.com:80/2013/123.html?id=1"));  //输出 http%3A%2F%2Fwww.baidu.com%3A80%2F2013%2F123.html%3Fid%3D1     Uri转义
            //Uri.EscapeUriString对空格进行了编码,也对中文进行了编码,但对冒号(:)、斜杠(/)和井号(#)未编码,所以此方法可以用于网址进行编码,但不能对参数进行编码
            //Uri.EscapeUriString对URI的网址部分编码,用Uri.EscapeDataString对URI中传递的参数进行编码。 
            Console.WriteLine(Uri.EscapeUriString("http://www.baidu.com:80/2013/123.html?id=1&你好"));//输出 http://www.baidu.com:80/2013/123.html?id=1&%E4%BD%A0%E5%A5%BD
            
            string str = "http%3A%2F%2Fwww.baidu.com%3A80%2F2013%2F123.html%3Fid%3D1";
            Console.WriteLine(Uri.UnescapeDataString(str)); //输出 http://www.baidu.com:80/2013/123.html?id=1 , 将Url还原成不转义的形式

            Console.WriteLine(Uri.FromHex('A'));    //输出 10  获取16进制数字的十进制值
            Console.WriteLine(Uri.HexEscape('2'));  //输出 %32 转换它的等效十六进制字符。 
            Console.WriteLine(Uri.IsHexDigit('F'));  //输出True 确定指定的字符是否为有效的十六进制数字。 

            int index = 0;
            if (Uri.IsHexEncoding("%75", index))
                Console.WriteLine("该编码代表的字符是 :{0}", Uri.HexUnescape("%75", ref index));
            else
                Console.WriteLine("这不是16禁止编码");

            //以下两个实例方法GetLeftPart与GetComponents都用于获取Uri中的一部分,可以是端口,方案,参数等等。
            Console.WriteLine(uri.GetComponents(UriComponents.Scheme,UriFormat.Unescaped)); //输出 http   获取Uri中的一部分,两个参数都是枚举
            Console.WriteLine(uri.GetLeftPart(UriPartial.Scheme));  //输出 http://

            Uri uri1 = new Uri("Http://www.baidu.com");
            Console.WriteLine(uri.IsBaseOf(uri1));  //输出 False
            Console.WriteLine(uri1.IsBaseOf(uri));  //输出 True

            //TryCreate也可用于相对路径转绝对路径,返回一个新的uri并且不成功时不报异常
            Uri uri2 = new Uri("http://www.baidu.com/a/b/c.html");
            Uri uri3;
            Uri.TryCreate(uri2,"../123.html",out uri3);
            Console.WriteLine(uri3);    //输出 http://www.baidu.com/a/123.html

            Uri uri4 = uri2.MakeRelativeUri(uri3);
            Console.WriteLine(uri4);    //输出..123/html
            //再来一个

            Uri uri5 = new Uri("http://www.baidu.com/a/b/d.html");
            Uri uri6 = new Uri("http://www.baidu.com/a/b/c.html");

            Uri uri7 = uri5.MakeRelativeUri(uri6);
            Console.WriteLine(uri7);    //输出 c.html //这样就表示目录相同,文件名不同,相对于第一个调用Uri来说的

            //确定文件是否不需要转义,没特殊字符就不需要转移
            //以下两个方法基本一致,只是一个是静态方法,一个是实例方法而已
            Console.WriteLine(Uri.IsWellFormedUriString("http://www.baidu.com", UriKind.Absolute));             //输出 True UriKind是一个枚举
            Console.WriteLine(Uri.IsWellFormedUriString("http://www.baidu.com/123.html?名字=张三", UriKind.Absolute));    //输出 False    表示需要转义
            
            Console.WriteLine(uri.IsWellFormedOriginalString());   //True 此 Uri 的字符串是否格式良好,以及它是否不需要进一步转义。 
            Uri uri8 = new Uri("http://www.baidu.com/123.html?名字=张三");
            Console.WriteLine(uri8.IsWellFormedOriginalString());   //输出False 
            Console.ReadKey();
        }
    }
复制代码

  有时间要看好点,这个类还是很有用的。

  另附上一个常用的功能,相对Uri转绝对Uri,这是是利用构造函数实现的,传入一个baseUri就能够实现,如如下代码:

复制代码
        static void Main(string[] args)
        {
            Uri uri = new Uri("http://www.jmeii.com/a/b/index.html");
            Uri uri2 = new Uri(uri,"../123.html");
            Console.WriteLine(uri2.ToString());     //输出http://www.jmeii.com/a/123.html

            Console.ReadKey();
        }
复制代码
<think>我们遇到了一个URI无效的错误。在.NET MAUI中使用HttpClient获取服务器文件大小时,出现“An invalid request URI was provided”错误。这个错误通常表示我们提供的URI字符串格式不正确。让我们一步步解决这个问题。 ## 错误原因分析 1. **URI格式错误**:提供的URL字符串可能包含非法字符或格式不正确 2. **未转义特殊字符**:URL中的特殊字符(如空格、中文等)未进行百分号编码 3. **协议头缺失**:缺少`http://`或`https://`协议前缀 4. **域名解析问题**:域名无法解析或格式错误 5. **端口号格式错误**:端口号超出范围或非数字 ## 解决方案 ### 步骤1:检查URI字符串格式 确保URI字符串是完整的URL,包含协议头(`http://`或`https://`)。例如: ```csharp string url = "https://example.com/file.zip"; // 正确 string invalidUrl = "example.com/file.zip"; // 错误,缺少协议头 ``` ### 步骤2:处理特殊字符 使用`Uri.EscapeDataString`或`Uri.EscapeUriString`对URL中的特殊字符进行编码: ```csharp string fileName = "文件.zip"; string encodedFileName = Uri.EscapeDataString(fileName); // 编码文件名部分 string fullUrl = $"https://example.com/{encodedFileName}"; ``` ### 步骤3:使用Uri验证 在发送请求前,使用`Uri`构造函数验证URI是否有效: ```csharp try { var uri = new Uri(url); // 如果url无效,这里会抛出异常 // 如果执行到这里,说明URI有效 } catch (UriFormatException ex) { // 处理无效URI Console.WriteLine($"无效URI: {ex.Message}"); } ``` ### 步骤4:完整示例代码 ```csharp using System; using System.Net.Http; using System.Threading.Tasks; public class FileSizeService { public async Task<long?> GetFileSizeAsync(string url) { try { // 验证URI格式 var uri = new Uri(url); // 这里会抛出异常如果URL无效 using (var client = new HttpClient()) { // 使用HEAD方法只获取头部信息(避免下载整个文件) var request = new HttpRequestMessage(HttpMethod.Head, uri); var response = await client.SendAsync(request); response.EnsureSuccessStatusCode(); // 从响应头获取文件大小 if (response.Content.Headers.ContentLength.HasValue) { return response.Content.Headers.ContentLength.Value; } } } catch (UriFormatException ex) { // 处理URI格式错误 Console.WriteLine($"URI格式错误: {ex.Message}"); // 这里可以记录日志或通知用户 } catch (Exception ex) { // 处理其他异常 Console.WriteLine($"错误: {ex.Message}"); } return null; } } ``` ### 步骤5:调用示例 ```csharp // 在ViewModel或代码中调用 var service = new FileSizeService(); long? size = await service.GetFileSizeAsync("https://example.com/大文件.zip"); if (size.HasValue) { Console.WriteLine($"文件大小: {size.Value} 字节"); } else { Console.WriteLine("无法获取文件大小"); } ``` ## 常见问题排查表 | 错误现象 | 可能原因 | 解决方案 | |---------|---------|---------| | `UriFormatException` | URL缺少协议头 | 添加`http://`或`https://` | | 包含空格的URL失效 | 空格未转义 | 使用`Uri.EscapeDataString`编码 | | 中文路径失效 | 中文字符未编码 | 对路径部分单独编码 | | 端口号无效 | 端口非数字或超出1-65535范围 | 检查端口号格式 | | 域名包含非法字符 | 域名有下划线等非法字符 | 使用Punycode编码或更换域名 | ## 高级技巧:处理重定向 有些服务器会返回重定向响应(302/301),此时需要处理重定向后的地址才能获取正确的文件大小。我们可以配置`HttpClientHandler`来自动跟随重定向: ```csharp var handler = new HttpClientHandler { AllowAutoRedirect = true // 默认就是true,确保开启 }; using (var client = new HttpClient(handler)) { // 其余代码相同 } ``` ## 性能优化建议 1. **使用HEAD请求**:只获取头部信息,不下载文件内容 2. **设置超时时间**:避免长时间等待 ```csharp client.Timeout = TimeSpan.FromSeconds(30); ``` 3. **重用HttpClient**:不要频繁创建和销毁,使用单例或`IHttpClientFactory` ## 相关问题 1. 如何在.NET MAUI中显示文件下载进度? 2. 如何处理HTTPS证书验证问题? 3. 如何实现大文件的分块下载? 4. 如何优化.NET MAUI中的网络请求性能? 5. 如何检测网络状态变化后自动重试请求?[^1] 6. 如何处理HTTP身份验证(如Basic Auth)?[^2] [^1]: 参见网络状态检测方案 [^2]: 需要添加`Authorization`请求头</think>在.NET MAUI中使用`HttpClient`获取服务器文件大小时遇到 **"An invalid request URI was provided"** 错误,通常是由URI格式问题引起的。以下是系统化的解决方案: --- ### 一、错误原因分析 1. **URI格式无效**: - 缺少协议头(如 `http://` 或 `https://`) - 包含非法字符(空格、中文等未编码字符) - 端口号格式错误(如 `http://example.com:abc/file`) 2. **特殊字符未转义**: ```csharp // 错误示例:包含未编码空格 string url = "https://example.com/my file.zip"; ``` 3. **平台兼容性问题**: - Android/iOS 对URI的严格校验 - 本地文件路径误用网络请求(如 `file://` 前缀) --- ### 二、解决方案(分步实现) #### 步骤1:标准化URI格式 使用 `Uri` 自动处理格式: ```csharp string rawUrl = "example.com/测 试.zip"; // 含空格和中文的示例 var validUri = new UriBuilder("https", rawUrl) { Port = -1 // 自动使用协议默认端口 }.Uri; // 输出:https://example.com/%E6%B5%8B%20%E8%AF%95.zip ``` #### 步骤2:手动编码特殊字符 ```csharp using System.Web; string EncodeUrl(string url) { // 拆分路径和查询参数 var uri = new Uri(url); string encodedPath = string.Join("/", uri.Segments.Select(s => HttpUtility.UrlEncode(s.Trim('/')))); return $"{uri.Scheme}://{uri.Host}{encodedPath}"; } // 使用示例 string safeUrl = EncodeUrl("https://example.com/文件 1.zip"); ``` #### 步骤3:安全获取文件大小(完整代码) ```csharp using System.Net; public async Task<long?> GetFileSizeAsync(string url) { try { // 验证并标准化URI if (!Uri.TryCreate(url, UriKind.Absolute, out var validUri)) throw new UriFormatException("无效URI"); using (var client = new HttpClient()) { // 仅请求头部(避免下载整个文件) var request = new HttpRequestMessage(HttpMethod.Head, validUri); var response = await client.SendAsync(request); response.EnsureSuccessStatusCode(); return response.Content.Headers.ContentLength; } } catch (UriFormatException ex) { // 记录日志或通知用户 Console.WriteLine($"URI错误: {ex.Message}"); return null; } } ``` --- ### 三、关键验证点 1. **协议头检查**: ```csharp if (!url.StartsWith("http://") && !url.StartsWith("https://")) url = "https://" + url; ``` 2. **端口号验证**: ```csharp if (uri.Port < 1 || uri.Port > 65535) throw new ArgumentException("端口号无效"); ``` 3. **Android兼容处理**: 在 `AndroidManifest.xml` 添加网络权限: ```xml <uses-permission android:name="android.permission.INTERNET" /> ``` --- ### 四、常见错误场景对照表 | 错误输入 | 修正后 | 原因 | |----------|--------|------| | `example.com/file` | `https://example.com/file` | 缺少协议头 | | `http://a b.com` | `http://a%20b.com` | 未编码空格 | | `https://中国.cn` | `https://xn--fiqs8s.cn` | 未编码中文域名(Punycode) | | `http://port:abc` | `http://port:80` | 非数字端口 | --- ### 五、高级调试技巧 1. 使用 `Uri.CheckHostName()` 验证域名: ```csharp UriHostNameType hostType = Uri.CheckHostName("example.com"); if (hostType == UriHostNameType.Unknown) throw new ArgumentException("无效域名"); ``` 2. 启用 `HttpClient` 日志(DEBUG模式): ```csharp var handler = new HttpClientHandler(); handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { Debug.WriteLine($"请求URL: {message.RequestUri}"); return true; // 仅调试用,生产环境应验证证书 }; ``` --- ### 相关问题 1. 如何在.NET MAUI中处理HTTPS证书验证失败?[^1] 2. 如何实现大文件的分块下载与断点续传? 3. 如何优化HttpClient在移动端的性能?[^2] 4. 如何检测服务器是否支持HEAD请求? 5. 网络请求超时如何自动重试?[^3] 6. 如何在不同网络状态(WiFi/移动数据)下调整下载策略?[^4] [^1]: 需配置`HttpClientHandler.ServerCertificateCustomValidationCallback` [^2]: 建议使用`IHttpClientFactory`管理连接池 [^3]: 可通过Polly库实现重试策略 [^4]: 使用`Connectivity`监听网络变化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值