Быстрая перемотка почти 9 лет с тех пор, как это было впервые задано, и в мире .NET Core и .NET Standard наиболее распространенными вариантами кодирования URL, по-видимому, являются WebUtility.UrlEncode (под System.Net
) и Uri.EscapeDataString . Судя по наиболее популярному ответу здесь и в других местах, Uri.EscapeDataString представляется предпочтительным. Но так ли это? Я сделал некоторый анализ, чтобы понять различия, и вот что я придумал:
В целях кодирования URL символы попадают в одну из 3 категорий: безрезультатно (допустимо в URL); зарезервировано (допустимо, но имеет особое значение, поэтому вы могли бы захотеть закодировать его); и все остальное (всегда должно быть закодировано).
Согласно RFC , зарезервированные символы: :/?#[]@!$&'()*+,;=
И незарезервированные символы алфавитно-цифровые и -._~
Вердикт
Uri.EscapeDataString четко определяет свою миссию:% -кодировать все зарезервированные и недопустимые символы. WebUtility.UrlEncode более неоднозначен как в определении, так и в реализации. Как ни странно, он кодирует некоторые зарезервированные символы, но не другие (почему скобки, а не скобки ??), и, что еще более странно, он кодирует этот невинно незарезервированный ~
символ.
Поэтому я согласен с популярным советом - используйте Uri.EscapeDataString , когда это возможно, и понимайте, что зарезервированные символы, такие как /
и ?
, будут закодированы. Если вам нужно иметь дело с потенциально большими строками, особенно с содержимым формы в кодировке URL, вам нужно либо воспользоваться WebUtility.UrlEncode и принять его причуды, либо иным образом обойти проблему.
РЕДАКТИРОВАТЬ: Я попытался исправить ВСЕ причуды, упомянутые выше в Flurl через Url.Encode
, Url.EncodeIllegalCharacters
и Url.Decode
статические методы. Они находятся в базовом пакете (который крошечный и не включает в себя весь HTTP), или можете свободно копировать их из исходного кода. Я приветствую любые комментарии / отзывы, которые у вас есть к ним.
Вот код, который я использовал, чтобы узнать, какие символы кодируются по-разному:
var diffs =
from i in Enumerable.Range(0, char.MaxValue + 1)
let c = (char)i
where !char.IsHighSurrogate(c)
let diff = new {
Original = c,
UrlEncode = WebUtility.UrlEncode(c.ToString()),
EscapeDataString = Uri.EscapeDataString(c.ToString()),
}
where diff.UrlEncode != diff.EscapeDataString
select diff;
foreach (var diff in diffs)
Console.WriteLine($"{diff.Original}\t{diff.UrlEncode}\t{diff.EscapeDataString}");