.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
是报错的:
第二个是正确的:
第一个地址是 .NET4.8 生成的, 第二个是 .NET5 生成的,相同的代码。。。
至于为什么会有这么大的差异,要从 HttpUtility.ParseQueryString
说起。
在 .NET4.8 下,HttpUtility.ParseQueryString
的返回是:System.Web.HttpValueCollection
类型的实例
在 .NET5 下, 返回类型是 System.Web.HttpUtility.HttpQSCollection
类型的实例。
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}");
}