Server.UrlEncode与HttpUtility.UrlEncode


Answers:



264

以前,UrlEncodeUri.EscapeDataString对这些方法非常头痛,建议您避免使用的任何变体,而应使用 -至少应具有可理解的行为。

让我们来看看...

HttpUtility.UrlEncode(" ") == "+" //breaks ASP.NET when used in paths, non-
                                  //standard, undocumented.
Uri.EscapeUriString("a?b=e") == "a?b=e" // makes sense, but rarely what you
                                        // want, since you still need to
                                        // escape special characters yourself

但是我个人最喜欢的必须是HttpUtility.UrlPathEncode-这东西真是难以理解。它编码:

  • “” ==>“%20”
  • “ 100%true” ==>“ 100 %% 20true”(好的,您的网址现在已损坏)
  • “ test A.aspx#anchor B” ==>“ test%20A.aspx #anchor%20B
  • “ test A.aspx?hmm#anchor B” ==>“ test%20A.aspx?hmm #anchor B ”(请注意与之前的转义序列的区别!

它还具有非常特别的MSDN文档“对URL字符串的路径部分进行编码,以实现从Web服务器到客户端的可靠HTTP传输。” -没有实际解释它的作用。您不太可能用Uzi射到自己的脚上...

简而言之,请坚持使用Uri.EscapeDataString


4
不幸的是,当对某些Web服务器进行HTTP请求时,它仍然不起作用-Uri.EscapeDataString()不会编码为“!”。或“'”,这与大多数浏览器的escape()实现方式不同...
克里斯·唐纳利

6
!和'字符不应该被编码;但是,如果有问题的Web服务器需要这样做,则很容易解决。避免使用javascript的转义功能-它本身就是越野车(对于双向旅行来说是不可能的)。参见xkr.us/articles/javascript/encode-compare-但总而言之;您可以改为使用encodeUriComponent(),其行为类似于EscapeDataString-它可预测且可逆地对字符串进行编码,并且也不进行编码!和'字符。
Eamon Nerbonne

2
这很旧,但是问题被撞到了首页,所以..... url字符串的路径部分是域和?之间的部分。或网址中的#。
Powerlord

2
@Tim:可能有几个?,谁说要编码,哪些用作分隔符?关于空间:在两种情况下,空间都在哈希中,因此查询片段的存在与否无关紧要。最后,破坏包含一个%的第二个示例中的Uri是不可原谅的。该UrlPathEncode方法是无聊的,绝不应该使用。
伊蒙·纳邦

1
我认为我在stackoverflow.com/a/13993486/237091上的答案可能会稍微了解UrlEncode / UrlPathEncode的预期用法。
斯科特·斯塔福德

60

自从首次提出此要求以来已经快9年了,在.NET Core和.NET Standard的世界中,似乎URL编码中最常用的选项是WebUtility.UrlEncode(在之下System.Net)和Uri.EscapeDataString。从此处和其他地方的最流行答案来看,Uri.EscapeDataString似乎更可取。但是吗?我做了一些分析以了解差异,这是我想出的:

  • WebUtility.UrlEncode将空间编码为+; Uri.EscapeDataString将其编码为%20
  • Uri.EscapeDataString百分之-编码!(),和*; WebUtility.UrlEncode才不是。
  • WebUtility.UrlEncode百分之-编码~; Uri.EscapeDataString才不是。
  • Uri.EscapeDataString抛出UriFormatException超过65,520个字符的字符串;WebUtility.UrlEncode才不是。(比您想象的更普遍的问题,尤其是在处理URL编码的表单数据时。)
  • Uri.EscapeDataStringUriFormatException高代理角色上抛出; WebUtility.UrlEncode才不是。(这是UTF-16的事情,可能不那么常见了。)

出于URL编码的目的,字符属于以下三类之一:不保留(URL中的合法字符);保留(合法,但具有特殊含义,因此您可能需要对其进行编码);以及其他所有内容(必须始终进行编码)。

根据RFC,保留字符为::/?#[]@!$&'()*+,;=

并且未保留的字符为字母数字和 -._~

判决

Uri.EscapeDataString明确定义了它的任务:%-编码所有保留和非法字符。WebUtility.UrlEncode在定义和实现上都更加模棱两可。奇怪的是,它对一些保留字符进行编码,但对其他字符不进行编码(为什么用括号而不是括号?),而陌生人仍然对无害的保留~字符进行编码。

因此,我同意流行的建议- 尽可能使用Uri.EscapeDataString,并了解保留字符(例如/和)?将被编码。如果您需要处理可能很大的字符串,尤其是处理URL编码的表单内容,则需要依靠WebUtility.UrlEncode并接受其古怪之处,否则可以解决此问题。


编辑:试图纠正所有的在上面提到的怪癖Flurl通过Url.EncodeUrl.EncodeIllegalCharactersUrl.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}");

2
这太棒了!
豪尔赫·阿吉雷

1
验证现代.net框架上建议的解决方案的出色工作。
Neowizard

应该提到的是,WebUtilityHttpUtility之间存在一些差异。对于六个实体,WebUtility使用大写字母,而HttpUtility使用小写字母。此外,.NET Framework“客户端配置文件”的旧子集版本中未包含HttpUtilityWebUtility可从.NET Framework 4.0获得。
tibx

28

请记住,您可能不应该使用任何一种方法。微软的反跨站点脚本库包括更换HttpUtility.UrlEncodeHttpUtility.HtmlEncode那都是更符合标准,更安全。作为奖励,您还可以获得一种JavaScriptEncode方法。


阅读所提供链接上的文档和常见问题解答后,我相信此答案是对数据进行编码的最佳,最安全的方法!非常感谢您的分享!
Sudhanshu Mishra

链接不再起作用。有哪些更换方法?
爱德华·布雷

@EdwardBrey这是Anti-Cross站点脚本库的最新版本:microsoft.com/en-au/download/details.aspx?
id=28589

11

Server.UrlEncode()可以提供与经典ASP的向后兼容性,

Server.UrlEncode(str);

等效于:

HttpUtility.UrlEncode(str, Response.ContentEncoding);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.