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<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 里, 也只是一個不公開的內部類。
這個類很簡單,只重寫了 NameValueCollectionToString 方法而已, 源碼在: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}");
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容