.NET48 代表 .NET FULL FRAMEWORK
.NET5 代表 .NET CORE 及以上版本
先看看這兩個地址:
http://www.baidu.com?y=%u4e2d
http://www.baidu.com?y=%e4%b8%ad
%u4e2d
= \u4e2d
= 中
生成這兩個地址的代碼是一樣的:
public static string SetUrlKeyValue2(this string url, IEnumerable<KeyValuePair<string, string>> kvs, bool ignoreCase = true, Encoding encoding = null)
{
if (kvs.IsNullOrEmpty())
return url;
url ??= "";
encoding ??= Encoding.UTF8;
var query = "";
var prefix = url;
if (url.IndexOf("?") > -1)
{
prefix = url.Substring(0, url.IndexOf("?"));
query = url.Substring(url.IndexOf("?"));
}
NameValueCollection ns = HttpUtility.ParseQueryString(query, encoding);
//#if NETFULL
// ns = new HttpQSCollection(ns);
//#endif
foreach (var kv in kvs)
ns.Set(kv.Key, kv.Value);
return HttpUtility.UrlPathEncode($"{prefix}?{ns}");
}
第一個地址是無效地址, 在瀏覽器里用 decodeURI
是報錯的:
NETFULL_DECODEURL.png
第二個是正確的:
NET5_DECODEURI.png
第一個地址是 .NET4.8 生成的, 第二個是 .NET5 生成的,相同的代碼。。。
至于為什么會有這么大的差異,要從 HttpUtility.ParseQueryString
說起。
在 .NET4.8 下,HttpUtility.ParseQueryString
的返回是:System.Web.HttpValueCollection
類型的實例
在 .NET5 下, 返回類型是 System.Web.HttpUtility.HttpQSCollection
類型的實例。
NET5.png
NETFULL.png
HttpQSCollection
類在 .NET 4.8 中不存在,在 .NET5 里, 也只是一個不公開的內部類。
這個類很簡單,只重寫了 NameValueCollection
的 ToString
方法而已, 源碼在:HttpUtility.cs 中可以找到:
internal sealed class HttpQSCollection : NameValueCollection
{
/// <summary>
///
/// </summary>
/// <param name="ns"></param>
public HttpQSCollection(NameValueCollection ns)
: base(ns)
{
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
int count = Count;
if (count == 0)
return "";
StringBuilder sb = new StringBuilder();
string[] keys = AllKeys;
for (int i = 0; i < count; i++)
{
sb.AppendFormat("{0}={1}&", keys[i], HttpUtility.UrlEncode(this[keys[i]]));
}
if (sb.Length > 0)
sb.Length--;
return sb.ToString();
}
}
把上面的代碼代入, 就可能修正 .NET4.8 的問題了。
public static string SetUrlKeyValue2(this string url, IEnumerable<KeyValuePair<string, string>> kvs, bool ignoreCase = true, Encoding encoding = null)
{
if (kvs.IsNullOrEmpty())
return url;
url ??= "";
encoding ??= Encoding.UTF8;
var query = "";
var prefix = url;
if (url.IndexOf("?") > -1)
{
prefix = url.Substring(0, url.IndexOf("?"));
query = url.Substring(url.IndexOf("?"));
}
NameValueCollection ns = HttpUtility.ParseQueryString(query, encoding);
#if NETFULL
ns = new HttpQSCollection(ns);
#endif
foreach (var kv in kvs)
ns.Set(kv.Key, kv.Value);
return HttpUtility.UrlPathEncode($"{prefix}?{ns}");
}