网站建设搜索优化app推广新闻营销,河源网站制作1993seo,404 重定向 wordpress,网站开发一般用C# 解析 URL URI 中的参数 文章目录 完整代码概述核心功能概述查询参数解析方法对比 核心方法实现解析1. 查询参数解析逻辑2. URL构建逻辑特殊场景处理说明测试用例验证使用注意事项 完整代码 namespace System
{using System.Collections.Generic;using System.Collections.Sp…C# 解析 URL URI 中的参数 文章目录 完整代码概述核心功能概述查询参数解析方法对比 核心方法实现解析1. 查询参数解析逻辑2. URL构建逻辑特殊场景处理说明测试用例验证使用注意事项 完整代码
namespace System
{using System.Collections.Generic;using System.Collections.Specialized;using System.Text;/// summary/// 函数see crefGetQueryDictionary(string, bool)/ 和 函数see crefGetQueryCollection(string, bool)/br //// 支持解析示例br //// ![CDATA[ https://www.google.com/index?page1langeng ]] br //// ![CDATA[ https://www.google.com/ ]] br //// ![CDATA[ https://www.google.com/index? ]] br //// ![CDATA[ https://www.google.com/index?pagetitleindex1langchangchar?id123 ]] br //// /summarypublic static class UrlHelper{#region Test 测试示例。/// summary/// 使用示例。/// /summary[System.Diagnostics.Conditional(DEBUG)]public static void Test(){TestGetQueryNormal();TestGetQuerySpecial();TestGetUrlStringNormal();}/// summary/// 常见的使用示例。解析URL中的参数。/// /summary[System.Diagnostics.Conditional(DEBUG)]public static void TestGetQueryNormal(){string urlTest1 https://www.google.com/index?page1langeng;string dictionaryBaseUrlTest1;var dictionaryTest1 GetQueryDictionary(urlTest1, out dictionaryBaseUrlTest1);System.Diagnostics.Debug.Assert(dictionaryBaseUrlTest1 https://www.google.com/index dictionaryTest1[page] 1 dictionaryTest1[lang] eng,GetQueryDictionary Test1);System.Diagnostics.Debug.Assert(GetUrlString(dictionaryBaseUrlTest1, dictionaryTest1) urlTest1,GetUrlString by Dictionary Test1);string collectionBaseUrlTest1;var collectionTest1 GetQueryCollection(urlTest1, out collectionBaseUrlTest1);System.Diagnostics.Debug.Assert(collectionBaseUrlTest1 https://www.google.com/index collectionTest1[page] 1 collectionTest1[lang] eng,GetQueryCollection Test1);System.Diagnostics.Debug.Assert(GetUrlString(collectionBaseUrlTest1, collectionTest1) urlTest1,GetUrlString by Collection Test1);string urlTest2 https://www.google.com/;string dictionaryBaseUrlTest2;GetQueryDictionary(urlTest2, out dictionaryBaseUrlTest2);System.Diagnostics.Debug.Assert(dictionaryBaseUrlTest2 https://www.google.com/,GetQueryDictionary Test2);string collectionBaseUrlTest2;GetQueryCollection(urlTest2, out collectionBaseUrlTest2);System.Diagnostics.Debug.Assert(collectionBaseUrlTest2 https://www.google.com/,GetQueryCollection Test2);string urlTest3 https://www.google.com/index?;string dictionaryBaseUrlTest3;GetQueryDictionary(urlTest3, out dictionaryBaseUrlTest3);System.Diagnostics.Debug.Assert(dictionaryBaseUrlTest3 https://www.google.com/index,GetQueryDictionary Test3);string collectionBaseUrlTest3;GetQueryCollection(urlTest3, out collectionBaseUrlTest3);System.Diagnostics.Debug.Assert(collectionBaseUrlTest3 https://www.google.com/index,GetQueryCollection Test4);}/// summary/// 不常见的使用示例。解析URL中的参数。/// /summary[System.Diagnostics.Conditional(DEBUG)]public static void TestGetQuerySpecial(){string urlSpecial4 https://www.google.com/index?pagetitleindex1langchangchar?id123;string dictionaryBaseUrlSpecial4;var dictionarySpecial4 GetQueryDictionary(urlSpecial4, out dictionaryBaseUrlSpecial4);System.Diagnostics.Debug.Assert(dictionaryBaseUrlSpecial4 https://www.google.com/index dictionarySpecial4[page] titleindex1 dictionarySpecial4[lang] dictionarySpecial4[chang] null dictionarySpecial4[char] ? dictionarySpecial4[id] 123,GetQueryDictionary UrlSpecial4);string collectionBaseUrlSpecial4;var collectionSpecial4 GetQueryCollection(urlSpecial4, out collectionBaseUrlSpecial4);System.Diagnostics.Debug.Assert(collectionBaseUrlSpecial4 https://www.google.com/index collectionSpecial4[page] titleindex1 collectionSpecial4[lang] collectionSpecial4[chang] null collectionSpecial4[char] ? collectionSpecial4[id] 123,GetQueryCollection UrlSpecial4);string urlSpecial5 https://www.google.com/index?page1langeng;string dictionaryBaseUrlSpecial5;var dictionarySpecial5 GetQueryDictionary(urlSpecial5, out dictionaryBaseUrlSpecial5);System.Diagnostics.Debug.Assert(dictionaryBaseUrlSpecial5 https://www.google.com/index dictionarySpecial5[page] 1 dictionarySpecial5[lang] eng,GetQueryDictionary UrlSpecial5);string collectionBaseUrlSpecial5;var collectionSpecial5 GetQueryCollection(urlSpecial5, out collectionBaseUrlSpecial5);System.Diagnostics.Debug.Assert(collectionBaseUrlSpecial5 https://www.google.com/index collectionSpecial5[page] 1 collectionSpecial5[lang] eng,GetQueryCollection UrlSpecial5);}/// summary/// 常见的使用示例。拼接URL的paramref namebaseUrl/和URL中的参数。/// /summary[System.Diagnostics.Conditional(DEBUG)]public static void TestGetUrlStringNormal(){string baseUrl1 https://www.google.com/index?page1langeng;System.Diagnostics.Debug.Assert(GetUrlString(baseUrl1, new Dictionarystring, string(){[TestKey1] TestValue1,[TestKey2] TestValue2,}) https://www.google.com/index?page1langengTestKey1TestValue1TestKey2TestValue2,GetUrlString by Dictionary BaseUrl1);System.Diagnostics.Debug.Assert(GetUrlString(baseUrl1, new NameValueCollection(){[TestKey1] TestValue1,[TestKey2] TestValue2,}) https://www.google.com/index?page1langengTestKey1TestValue1TestKey2TestValue2,GetUrlString by Collection BaseUrl1);string baseUrl2 https://www.google.com/index;System.Diagnostics.Debug.Assert(GetUrlString(baseUrl2, new Dictionarystring, string(){[TestKey1] TestValue1,[TestKey2] TestValue2,}) https://www.google.com/index?TestKey1TestValue1TestKey2TestValue2,GetUrlString by Dictionary BaseUrl2);System.Diagnostics.Debug.Assert(GetUrlString(baseUrl2, new NameValueCollection(){[TestKey1] TestValue1,[TestKey2] TestValue2,}) https://www.google.com/index?TestKey1TestValue1TestKey2TestValue2,GetUrlString by Collection BaseUrl2);}#endregion Test 测试示例。/// summary/// 解析URL中的参数。会覆盖重复键的值。br //// 注意在see crefDictionary{TKey, TValue}/中/// 通过see crefDictionary{TKey, TValue}/的![CDATA[ this[TKey key] ]]/// 直接读取不存在的键值对时会抛出异常。br //// /summary/// param nameurl/param/// param nameignoreCase/param/// returns/returnspublic static Dictionarystring, string GetQueryDictionary(string url, bool ignoreCase false){string baseUrl;return GetQueryDictionary(url, out baseUrl, ignoreCase);}/// summary/// 解析URL中的参数。会覆盖重复键的值。br //// 注意在see crefDictionary{TKey, TValue}/中/// 通过see crefDictionary{TKey, TValue}/的![CDATA[ this[TKey key] ]]/// 直接读取不存在的键值对时会抛出异常。br //// /summary/// param nameurl/param/// param namebaseUrl URL中符号“?”的前面部分。/param/// param nameignoreCase/param/// returns/returnspublic static Dictionarystring, string GetQueryDictionary(string url, out string baseUrl, bool ignoreCase false){StringComparer comparer;if (ignoreCase){comparer StringComparer.InvariantCultureIgnoreCase;}else{comparer StringComparer.InvariantCulture;}return GetQueryDictionary(url, out baseUrl, comparer);}/// summary/// 解析URL中的参数。会覆盖重复键的值。br //// 注意在see crefDictionary{TKey, TValue}/中/// 通过see crefDictionary{TKey, TValue}/的![CDATA[ this[TKey key] ]]/// 直接读取不存在的键值对时会抛出异常。br //// /summary/// param nameurl/param/// param namebaseUrl URL中符号“?”的前面部分。/param/// param namecomparer/param/// returns/returnspublic static Dictionarystring, string GetQueryDictionary(string url, out string baseUrl, StringComparer comparer){baseUrl null;// 第一个“?”符号的下标。// 用于支持参数中包括“?”符号的URL。int indexQuestionMark url.IndexOf(?);int countQuery url.Length - indexQuestionMark - 1;Dictionarystring, string info null;// 如果URL中包括有效的参数。if (indexQuestionMark -1 countQuery 0){string queryString url.Substring(indexQuestionMark 1, countQuery);// 为空的键值对没有意义所以舍弃为空的键值对。string[] keyAndValuePairs queryString.Split(new char[] { }/*, StringSplitOptions.RemoveEmptyEntries*/);info new Dictionarystring, string(keyAndValuePairs.Length 1, comparer);foreach (var pair in keyAndValuePairs){// 第一个“”符号的下标。// 用于支持value中包括“”符号的参数。int indexEquals pair.IndexOf();// 如果包含“”符号。if (indexEquals -1){string key pair.Substring(0, indexEquals);key Uri.UnescapeDataString(key);int countValue pair.Length - indexEquals - 1;// 避免“”符号后面没有内容时indexEquals 1超出数组的有效索引。string value (countValue 0) ? string.Empty : pair.Substring(indexEquals 1, countValue);value Uri.UnescapeDataString(value);info[key] value;}// 用关键字保存特殊参数。else{info[pair] null;}}}info info ?? new Dictionarystring, string(1, comparer);if (indexQuestionMark 0 || indexQuestionMark url.Length){indexQuestionMark url.Length;}// URL中符号“?”的前面部分。baseUrl url.Substring(0, indexQuestionMark);return info;}/// summary/// 解析URL中的参数。支持重复键。br //// 注意在see crefNameValueCollection/中直接读取不存在的键值对时返回 null 不会抛出异常。br //// /summary/// param nameurl/param/// param nameignoreCase/param/// returns/returnspublic static NameValueCollection GetQueryCollection(string url, bool ignoreCase false){string baseUrl;return GetQueryCollection(url, out baseUrl, ignoreCase);}/// summary/// 解析URL中的参数。支持重复键。br //// 注意在see crefNameValueCollection/中直接读取不存在的键值对时返回 null 不会抛出异常。br //// /summary/// param nameurl/param/// param namebaseUrl URL中符号“?”的前面部分。/param/// param nameignoreCase/param/// returns/returnspublic static NameValueCollection GetQueryCollection(string url, out string baseUrl, bool ignoreCase false){StringComparer comparer;if (ignoreCase){comparer StringComparer.InvariantCultureIgnoreCase;}else{comparer StringComparer.InvariantCulture;}return GetQueryCollection(url, out baseUrl, comparer);}/// summary/// 解析URL中的参数。支持重复键。br //// 注意在see crefNameValueCollection/中直接读取不存在的键值对时返回 null 不会抛出异常。br //// /summary/// param nameurl/param/// param namebaseUrl URL中符号“?”的前面部分。/param/// param namecomparer/param/// returns/returnspublic static NameValueCollection GetQueryCollection(string url, out string baseUrl, StringComparer comparer){// 第一个“?”符号的下标。// 用于支持参数中包括“?”符号的URL。int indexQuestionMark url.IndexOf(?);int countQuery url.Length - indexQuestionMark - 1;NameValueCollection info null;// 如果URL中包括有效的参数。if (indexQuestionMark -1 countQuery 0){string queryString url.Substring(indexQuestionMark 1, countQuery);// 为空的键值对没有意义所以舍弃为空的键值对。string[] keyAndValuePairs queryString.Split(new char[] { }/*, StringSplitOptions.RemoveEmptyEntries*/);info new NameValueCollection(keyAndValuePairs.Length 1, comparer);foreach (var pair in keyAndValuePairs){// 第一个“”符号的下标。// 用于支持value中包括“”符号的参数。int indexEquals pair.IndexOf();// 如果包含“”符号。if (indexEquals -1){string key pair.Substring(0, indexEquals);key Uri.UnescapeDataString(key);int countValue pair.Length - indexEquals - 1;// 避免“”符号后面没有内容时indexEquals 1超出数组的有效索引。string value (countValue 0) ? string.Empty : pair.Substring(indexEquals 1, countValue);value Uri.UnescapeDataString(value);info.Add(key, value);}// 用关键字保存特殊参数。else{info.Add(pair, null);}}}info info ?? new NameValueCollection(1, comparer);if (indexQuestionMark 0 || indexQuestionMark url.Length){indexQuestionMark url.Length;}// URL中符号“?”的前面部分。baseUrl url.Substring(0, indexQuestionMark);return info;}/// summary/// 拼接URL的paramref namebaseUrl/可以是URL中符号“?”的前面部分也可以是已经包含参数的URL和URL中的参数。/// /summary/// param namebaseUrl/param/// param nameparameters/param/// returns/returnspublic static string GetUrlString(string baseUrl, ICollectionKeyValuePairstring, string parameters){if (parameters ! null parameters.Count 0){var indexEndSplit baseUrl.LastIndexOf(/);if (indexEndSplit 0){indexEndSplit 0;}StringBuilder builder new StringBuilder(baseUrl.Length 128 1);var indexQuestionMark baseUrl.IndexOf(?, indexEndSplit);if (indexQuestionMark 0){builder.Append(baseUrl);bool hasQueryItem false;bool addQuestionMark true;GetUrlQueryStringCore(parameters, builder, hasQueryItem, addQuestionMark);}else{builder.Append(baseUrl);bool hasQueryItem indexQuestionMark baseUrl.Length - 1;bool addQuestionMark false;GetUrlQueryStringCore(parameters, builder, hasQueryItem, addQuestionMark);}return builder.ToString();}return baseUrl;}/// summary/// 拼接URL的paramref namebaseUrl/可以是URL中符号“?”的前面部分也可以是已经包含参数的URL和URL中的参数。/// /summary/// param namebaseUrl/param/// param nameparameters/param/// returns/returnspublic static string GetUrlString(string baseUrl, NameValueCollection parameters){if (parameters ! null parameters.Count 0){var indexEndSplit baseUrl.LastIndexOf(/);if (indexEndSplit 0){indexEndSplit 0;}StringBuilder builder new StringBuilder(baseUrl.Length 128 1);var indexQuestionMark baseUrl.IndexOf(?, indexEndSplit);if (indexQuestionMark 0){builder.Append(baseUrl);bool hasQueryItem false;bool addQuestionMark true;GetUrlQueryStringCore(parameters, builder, hasQueryItem, addQuestionMark);}else{builder.Append(baseUrl);bool hasQueryItem indexQuestionMark baseUrl.Length - 1;bool addQuestionMark false;GetUrlQueryStringCore(parameters, builder, hasQueryItem, addQuestionMark);}return builder.ToString();}return baseUrl;}public static string GetUrlQueryString(ICollectionKeyValuePairstring, string parameters, bool addQuestionMark){StringBuilder builder new StringBuilder(128);bool hasQueryItem false;GetUrlQueryStringCore(parameters, builder, hasQueryItem, addQuestionMark);return builder.ToString();}public static string GetUrlQueryString(NameValueCollection parameters, bool addQuestionMark){StringBuilder builder new StringBuilder(128);bool hasQueryItem false;GetUrlQueryStringCore(parameters, builder, hasQueryItem, addQuestionMark);return builder.ToString();}private static void GetUrlQueryStringCore(ICollectionKeyValuePairstring, string parameters, StringBuilder builder, bool hasQueryItem, bool addQuestionMark){foreach (KeyValuePairstring, string item in parameters){GetUrlQueryStringForAddParameterBefore(builder, ref hasQueryItem, addQuestionMark);builder.Append(Uri.EscapeDataString(item.Key));if (item.Value ! null){builder.Append();builder.Append(Uri.EscapeDataString(item.Value));}}}private static void GetUrlQueryStringCore(NameValueCollection parameters, StringBuilder builder, bool hasQueryItem, bool addQuestionMark){foreach (object itemKeyObj in parameters.Keys){string itemKey itemKeyObj?.ToString();if (itemKey ! null){var itemValues parameters.GetValues(itemKey);if (itemValues null){GetUrlQueryStringForAddParameterBefore(builder, ref hasQueryItem, addQuestionMark);builder.Append(Uri.EscapeDataString(itemKey));}else{foreach (var itemValue in itemValues){GetUrlQueryStringForAddParameterBefore(builder, ref hasQueryItem, addQuestionMark);builder.Append(Uri.EscapeDataString(itemKey));if (itemValue ! null){builder.Append();builder.Append(Uri.EscapeDataString(itemValue));}}}}}}private static void GetUrlQueryStringForAddParameterBefore(StringBuilder builder, ref bool hasQueryItem, bool addQuestionMark){if (hasQueryItem){builder.Append();}else{hasQueryItem true;if (addQuestionMark){builder.Append(?);}}}}
}
概述
核心功能概述 查询参数解析 GetQueryDictionary()将URL查询参数解析为字典键值唯一后值覆盖前值GetQueryCollection()将URL查询参数解析为集合支持多值键 URL构建 GetUrlString()将基础URL与参数集合/字典拼接成完整URL 特殊支持 处理含特殊字符的键值如?、支持无值参数如key处理参数中出现的等号和问号
查询参数解析方法对比
特性GetQueryDictionaryGetQueryCollection返回值类型Dictionarystring, stringNameValueCollection键唯一性✔️后值覆盖前值✖️支持多值键读取不存在键抛出异常返回null参数格式键值值中可含键值值中可含无值参数处理键→null键→null
核心方法实现解析
1. 查询参数解析逻辑
// 解析字典示例
int indexQuestionMark url.IndexOf(?);
if (indexQuestionMark -1)
{string queryString url.Substring(indexQuestionMark 1);string[] pairs queryString.Split();foreach (var pair in pairs){int indexEquals pair.IndexOf();if (indexEquals -1){string key Uri.UnescapeDataString(pair.Substring(0, indexEquals));string value Uri.UnescapeDataString(pair.Substring(indexEquals 1));dict[key] value; // 字典直接赋值覆盖}else{dict[pair] null; // 无值参数处理}}
}
baseUrl url.Substring(0, indexQuestionMark);2. URL构建逻辑
// URL拼接核心逻辑
private static void GetUrlQueryStringCore(NameValueCollection parameters, StringBuilder builder)
{foreach (string key in parameters.Keys){string[] values parameters.GetValues(key);foreach (string value in values){// 添加分隔符?或if (builder.Length baseUrlLength) builder.Append();else if (needQuestionMark) builder.Append(?);builder.Append(Uri.EscapeDataString(key));if (value ! null){builder.Append();builder.Append(Uri.EscapeDataString(value));}}}
}特殊场景处理说明 值中含等号 使用首次出现的分割键值 // 示例参数titleindex1
// 解析结果keytitle, valueindex1
int indexEquals pair.IndexOf();无值参数 被解析为key → null // 示例URLhttps://site.com?key1key2val
// 解析结果key1null, key2val问号处理 仅识别第一个?作为查询起始 // 示例https://site.com?param?
// 正确解析param?
int indexQuestionMark url.IndexOf(?);测试用例验证
测试场景
1. 标准URL解析✓ https://site.com?k1v1k2v2 → k1v1, k2v22. 特殊字符处理✓ https://site.com?key? → key?✓ https://site.com?k123 → k1233. 边界情况✓ https://site.com? (空参数) → 空集合✓ https://site.com (无参数) → 空集合4. URL重建验证✓ 解析后重建URL应与原始URL一致使用注意事项 字典读取风险 // 安全读取方式
if (dict.TryGetValue(key, out var value)) { ... }编码规范 使用Uri.EscapeDataString处理特殊字符使用Uri.UnescapeDataString反向解码