HttpUtility.ParseQueryString 在.NET48 和 NET5 中的不同表现

.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> 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 里, 也只是一个不公开的内部类。
这个类很简单,只重写了 NameValueCollectionToString 方法而已, 源码在:HttpUtility.cs 中可以找到:

    internal sealed class HttpQSCollection : NameValueCollection
    {

        /// 
        /// 
        /// 
        /// 
        public HttpQSCollection(NameValueCollection ns)
            : base(ns)
        {
        }

        /// 
        /// 
        /// 
        /// 
        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> 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}");
}

你可能感兴趣的:(HttpUtility.ParseQueryString 在.NET48 和 NET5 中的不同表现)