使用C#进行URL编码

我有一个我为朋友开发的应用程序。 它发送一个POST请求到VB论坛软件,并logging下一个人(没有设置cookie或任何东西)。

一旦用户login,我创build一个variables,在本地机器上创build一个path。

C:\ tempfolder \日\用户名

问题是有些用户名正在抛出“非法字符”exception。 例如,如果我的用户名是mas|fenix它会抛出一个exception。

 Path.Combine( _ Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), _ DateTime.Now.ToString("ddMMyyhhmm") + "-" + form1.username) 

我不想从string中删除它,但是在服务器上通过FTP创build一个带有用户名的文件夹。 这导致了我的第二个问题。 如果我在服务器上创build文件夹,我可以离开“非法字符”? 我只问这是因为服务器是基于Linux的,我不确定Linux是否接受它。

编辑:看来,URL编码不是我想要的..这是我想要做的:

 old username = mas|fenix new username = mas%xxfenix 

其中%xx是ASCII值或任何其他可轻易识别字符的值。

编辑:请注意,这个答案现在是过时的。 请参阅下面的Siarhei Kuchuk的回答,以获得更好的解决方法

UrlEncoding会做你在这里build议的。 用C#,你只需使用HttpUtility ,如前所述。

你也可以正则expression式中的非法字符,然后replace,但是这变得复杂得多,因为你必须有某种forms的状态机(例如switch … case)才能用正确的字符replace。 由于UrlEncode做到这一点,所以很容易。

至于Linux和windows,Linux中有一些不在Windows的字符是可以接受的,但是我不担心,因为使用UrlDecode解码Urlstring可以返回文件夹名称,所以你可以往返变化。

我一直在尝试.NET提供的URL编码的各种方法。 也许下面的表格将是有用的(作为我写的一个testing应用程序的输出):

 Unencoded UrlEncoded UrlEncodedUnicode UrlPathEncoded EscapedDataString EscapedUriString HtmlEncoded HtmlAttributeEncoded HexEscaped AAAAAAAA %41 BBBBBBBB %42 aaaaaaaa %61 bbbbbbbb %62 0 0 0 0 0 0 0 0 %30 1 1 1 1 1 1 1 1 %31 [space] + + %20 %20 %20 [space] [space] %20 ! ! ! ! ! ! ! ! %21 " %22 %22 " %22 %22 &quot; &quot; %22 # %23 %23 # %23 # # # %23 $ %24 %24 $ %24 $ $ $ %24 % %25 %25 % %25 %25 % % %25 & %26 %26 & %26 & &amp; &amp; %26 ' %27 %27 ' ' ' &#39; &#39; %27 ( ( ( ( ( ( ( ( %28 ) ) ) ) ) ) ) ) %29 * * * * %2A * * * %2A + %2b %2b + %2B + + + %2B , %2c %2c , %2C , , , %2C - - - - - - - - %2D . . . . . . . . %2E / %2f %2f / %2F / / / %2F : %3a %3a : %3A : : : %3A ; %3b %3b ; %3B ; ; ; %3B < %3c %3c < %3C %3C &lt; &lt; %3C = %3d %3d = %3D = = = %3D > %3e %3e > %3E %3E &gt; > %3E ? %3f %3f ? %3F ? ? ? %3F @ %40 %40 @ %40 @ @ @ %40 [ %5b %5b [ %5B %5B [ [ %5B \ %5c %5c \ %5C %5C \ \ %5C ] %5d %5d ] %5D %5D ] ] %5D ^ %5e %5e ^ %5E %5E ^ ^ %5E _ _ _ _ _ _ _ _ %5F ` %60 %60 ` %60 %60 ` ` %60 { %7b %7b { %7B %7B { { %7B | %7c %7c | %7C %7C | | %7C } %7d %7d } %7D %7D } } %7D ~ %7e %7e ~ ~ ~ ~ ~ %7E Ā %c4%80 %u0100 %c4%80 %C4%80 %C4%80 Ā Ā [OoR] ā %c4%81 %u0101 %c4%81 %C4%81 %C4%81 ā ā [OoR] Ē %c4%92 %u0112 %c4%92 %C4%92 %C4%92 Ē Ē [OoR] ē %c4%93 %u0113 %c4%93 %C4%93 %C4%93 ē ē [OoR] Ī %c4%aa %u012a %c4%aa %C4%AA %C4%AA Ī Ī [OoR] ī %c4%ab %u012b %c4%ab %C4%AB %C4%AB ī ī [OoR] Ō %c5%8c %u014c %c5%8c %C5%8C %C5%8C Ō Ō [OoR] ō %c5%8d %u014d %c5%8d %C5%8D %C5%8D ō ō [OoR] Ū %c5%aa %u016a %c5%aa %C5%AA %C5%AA Ū Ū [OoR] ū %c5%ab %u016b %c5%ab %C5%AB %C5%AB ū ū [OoR] 

这些列表示编码如下:

  • UrlEncoded: HttpUtility.UrlEncode

  • UrlEncodedUnicode: HttpUtility.UrlEncodeUnicode

  • UrlPathEncoded: HttpUtility.UrlPathEncode

  • EscapedDataString: Uri.EscapeDataString

  • EscapedUriString: Uri.EscapeUriString

  • HtmlEncoded: HttpUtility.HtmlEncode

  • HtmlAttributeEncoded: HttpUtility.HtmlAttributeEncode

  • Hexescaped: Uri.HexEscape

笔记:

  1. HexEscape只能处理前255个字符。 因此它为拉丁A扩展字符(例如Â)抛出一个ArgumentOutOfRangeexception。

  2. 这个表是在.NET 4.0中生成的(请参阅下面的Levi Botelho的评论,说.NET 4.5中的编码略有不同)。

编辑:

我已经添加了.NET 4.5的编码的第二个表。 看到这个答案: https : //stackoverflow.com/a/21771206/216440

编辑2:

因为人们似乎很欣赏这些表格,所以我想你可能会喜欢生成表格的源代码,所以你可以自己玩。 这是一个简单的C#控制台应用程序,它可以以.NET 4.0或4.5为目标:

 using System; using System.Collections.Generic; using System.Text; // Need to add a Reference to the System.Web assembly. using System.Web; namespace UriEncodingDEMO2 { class Program { static void Main(string[] args) { EncodeStrings(); Console.WriteLine(); Console.WriteLine("Press any key to continue..."); Console.Read(); } public static void EncodeStrings() { string stringToEncode = "ABCD" + "abcd" + "0123" + " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" + "ĀāĒēĪīŌōŪū"; // Need to set the console encoding to display non-ASCII characters correctly (eg the // Latin A-Extended characters such as ĀāĒē...). Console.OutputEncoding = Encoding.UTF8; // Will also need to set the console font (in the console Properties dialog) to a font // that displays the extended character set correctly. // The following fonts all display the extended characters correctly: // Consolas // DejaVu Sana Mono // Lucida Console // Also, in the console Properties, set the Screen Buffer Size and the Window Size // Width properties to at least 140 characters, to display the full width of the // table that is generated. Dictionary<string, Func<string, string>> columnDetails = new Dictionary<string, Func<string, string>>(); columnDetails.Add("Unencoded", (unencodedString => unencodedString)); columnDetails.Add("UrlEncoded", (unencodedString => HttpUtility.UrlEncode(unencodedString))); columnDetails.Add("UrlEncodedUnicode", (unencodedString => HttpUtility.UrlEncodeUnicode(unencodedString))); columnDetails.Add("UrlPathEncoded", (unencodedString => HttpUtility.UrlPathEncode(unencodedString))); columnDetails.Add("EscapedDataString", (unencodedString => Uri.EscapeDataString(unencodedString))); columnDetails.Add("EscapedUriString", (unencodedString => Uri.EscapeUriString(unencodedString))); columnDetails.Add("HtmlEncoded", (unencodedString => HttpUtility.HtmlEncode(unencodedString))); columnDetails.Add("HtmlAttributeEncoded", (unencodedString => HttpUtility.HtmlAttributeEncode(unencodedString))); columnDetails.Add("HexEscaped", (unencodedString => { // Uri.HexEscape can only handle the first 255 characters so for the // Latin A-Extended characters, such as A, it will throw an // ArgumentOutOfRange exception. try { return Uri.HexEscape(unencodedString.ToCharArray()[0]); } catch { return "[OoR]"; } })); char[] charactersToEncode = stringToEncode.ToCharArray(); string[] stringCharactersToEncode = Array.ConvertAll<char, string>(charactersToEncode, (character => character.ToString())); DisplayCharacterTable<string>(stringCharactersToEncode, columnDetails); } private static void DisplayCharacterTable<TUnencoded>(TUnencoded[] unencodedArray, Dictionary<string, Func<TUnencoded, string>> mappings) { foreach (string key in mappings.Keys) { Console.Write(key.Replace(" ", "[space]") + " "); } Console.WriteLine(); foreach (TUnencoded unencodedObject in unencodedArray) { string stringCharToEncode = unencodedObject.ToString(); foreach (string columnHeader in mappings.Keys) { int columnWidth = columnHeader.Length + 1; Func<TUnencoded, string> encoder = mappings[columnHeader]; string encodedString = encoder(unencodedObject); // ASSUMPTION: Column header will always be wider than encoded string. Console.Write(encodedString.Replace(" ", "[space]").PadRight(columnWidth)); } Console.WriteLine(); } } } } 

您应该只编码可能无效的用户名或URL的其他部分。 URL编码的URL可能会导致问题,因为这样的事情:

 string url = HttpUtility.UrlEncode("http://www.google.com/search?q=Example"); 

会屈服

HTTP%3A%2F%2fwww.google.com%2fsearch%3fq%3dExample

这显然不会很好。 相反,您应该只在查询string中编码键/值对的值,如下所示:

 string url = "http://www.google.com/search?q=" + HttpUtility.UrlEncode("Example"); 

希望有帮助。 另外,像teedyay提到的,你仍然需要确保非法的文件名字符被删除,否则文件系统将不会喜欢这个path。

.NET Framework 4.5以来,您可以使用WebUtility.UrlEncode

首先,它驻留在System.dll ,因此不需要任何其他引用。

其次,它正确地转义URL的字符 ,不像Uri.EscapeUriString (见drweb86的回答评论)。

第三,它不像Uri.EscapeDataString (参见相关问题 )那样对string的长度没有任何限制 ,所以它可以用于POST请求。

第四,它可以在WinRT上使用 ,不像HttpUtility (见相关问题 )。

更好的方法是使用

 Uri.EscapeUriString 

不参考.net 4的完整档案。

url编码在.NET中很容易。 使用:

 System.Web.HttpUtility.UrlEncode(string url) 

如果这将被解码以获得文件夹名称,您仍然需要排除文件夹名称中不能使用的字符(*,?,/等)

Levi Botelho评论说,之前生成的编码表在.NET 4.5中不再准确,因为编码在.NET 4.0和4.5之间稍有改变。 所以我重新创build了.NET 4.5的表格:

 Unencoded UrlEncoded UrlEncodedUnicode UrlPathEncoded WebUtilityUrlEncoded EscapedDataString EscapedUriString HtmlEncoded HtmlAttributeEncoded WebUtilityHtmlEncoded HexEscaped AAAAAAAAAA %41 BBBBBBBBBB %42 aaaaaaaaaa %61 bbbbbbbbbb %62 0 0 0 0 0 0 0 0 0 0 %30 1 1 1 1 1 1 1 1 1 1 %31 [space] + + %20 + %20 %20 [space] [space] [space] %20 ! ! ! ! ! %21 ! ! ! ! %21 " %22 %22 " %22 %22 %22 &quot; &quot; &quot; %22 # %23 %23 # %23 %23 # # # # %23 $ %24 %24 $ %24 %24 $ $ $ $ %24 % %25 %25 % %25 %25 %25 % % % %25 & %26 %26 & %26 %26 & &amp; &amp; &amp; %26 ' %27 %27 ' %27 %27 ' &#39; &#39; &#39; %27 ( ( ( ( ( %28 ( ( ( ( %28 ) ) ) ) ) %29 ) ) ) ) %29 * * * * * %2A * * * * %2A + %2b %2b + %2B %2B + + + + %2B , %2c %2c , %2C %2C , , , , %2C - - - - - - - - - - %2D . . . . . . . . . . %2E / %2f %2f / %2F %2F / / / / %2F : %3a %3a : %3A %3A : : : : %3A ; %3b %3b ; %3B %3B ; ; ; ; %3B < %3c %3c < %3C %3C %3C &lt; &lt; &lt; %3C = %3d %3d = %3D %3D = = = = %3D > %3e %3e > %3E %3E %3E &gt; > &gt; %3E ? %3f %3f ? %3F %3F ? ? ? ? %3F @ %40 %40 @ %40 %40 @ @ @ @ %40 [ %5b %5b [ %5B %5B [ [ [ [ %5B \ %5c %5c \ %5C %5C %5C \ \ \ %5C ] %5d %5d ] %5D %5D ] ] ] ] %5D ^ %5e %5e ^ %5E %5E %5E ^ ^ ^ %5E _ _ _ _ _ _ _ _ _ _ %5F ` %60 %60 ` %60 %60 %60 ` ` ` %60 { %7b %7b { %7B %7B %7B { { { %7B | %7c %7c | %7C %7C %7C | | | %7C } %7d %7d } %7D %7D %7D } } } %7D ~ %7e %7e ~ %7E ~ ~ ~ ~ ~ %7E Ā %c4%80 %u0100 %c4%80 %C4%80 %C4%80 %C4%80 Ā Ā Ā [OoR] ā %c4%81 %u0101 %c4%81 %C4%81 %C4%81 %C4%81 ā ā ā [OoR] Ē %c4%92 %u0112 %c4%92 %C4%92 %C4%92 %C4%92 Ē Ē Ē [OoR] ē %c4%93 %u0113 %c4%93 %C4%93 %C4%93 %C4%93 ē ē ē [OoR] Ī %c4%aa %u012a %c4%aa %C4%AA %C4%AA %C4%AA Ī Ī Ī [OoR] ī %c4%ab %u012b %c4%ab %C4%AB %C4%AB %C4%AB ī ī ī [OoR] Ō %c5%8c %u014c %c5%8c %C5%8C %C5%8C %C5%8C Ō Ō Ō [OoR] ō %c5%8d %u014d %c5%8d %C5%8D %C5%8D %C5%8D ō ō ō [OoR] Ū %c5%aa %u016a %c5%aa %C5%AA %C5%AA %C5%AA Ū Ū Ū [OoR] ū %c5%ab %u016b %c5%ab %C5%AB %C5%AB %C5%AB ū ū ū [OoR] 

这些列表示编码如下:

  • UrlEncoded: HttpUtility.UrlEncode
  • UrlEncodedUnicode: HttpUtility.UrlEncodeUnicode
  • UrlPathEncoded: HttpUtility.UrlPathEncode
  • WebUtilityUrlEncoded: WebUtility.UrlEncode
  • EscapedDataString: Uri.EscapeDataString
  • EscapedUriString: Uri.EscapeUriString
  • HtmlEncoded: HttpUtility.HtmlEncode
  • HtmlAttributeEncoded: HttpUtility.HtmlAttributeEncode
  • WebUtilityHtmlEncoded: WebUtility.HtmlEncode
  • Hexescaped: Uri.HexEscape

笔记:

  1. HexEscape只能处理前255个字符。 因此它为拉丁A扩展字符(例如Â)抛出一个ArgumentOutOfRangeexception。

  2. 该表是在.NET 4.5中生成的(请参阅https://stackoverflow.com/a/11236038/216440 ,了解与.NET 4.0及以下版本相关的编码)。

编辑:

  1. 由于Discord的回答,我添加了.NET 4.5中引入的新的WebUtility UrlEncode和HtmlEncode方法。

如果您看不到System.Web,请更改您的项目设置。 目标框架应该是“.NET Framework 4”而不是“.NET Framework 4 Client Profile”

UrlEncode的.NET实现不符合RFC 3986。

  1. 有些字符不是编码,但应该是。 !()*字符在RFC的第2.2节中列出为必须编码的保留字符,但.NET无法对这些字符进行编码。

  2. 一些字符被编码,但不应该是。 .-_字符在RFC的第2.2节中没有列为保留字符,不应该被编码,但.NET错误地编码了这些字符。

  3. RFC规定为了保持一致,实现应该使用大写的HEXDIG,其中.NET生成小写的HEXDIG。

理想情况下,这些将在一个名为“FileNaming”的类中进行,或者也可以将Encode重命名为“FileNameEncode”。 注意:这些不是用来处理完整path,只是文件夹和/或文件名。 理想情况下,你会首先拆分(“/”)你的完整path,然后检查件。 显然,如果不是联合,你可以将“%”字符添加到Windows不允许的字符列表中,但是我认为这样做更有帮助/可读/事实性。 Decode()是完全一样的,但切换Replace(Uri.HexEscape(s [0]),s)与字符“逃脱”。

 public static List<string> urlEncodedCharacters = new List<string> { "/", "\\", "<", ">", ":", "\"", "|", "?", "%" //and others, but not * }; //Since this is a superset of urlEncodedCharacters, we won't be able to only use UrlEncode() - instead we'll use HexEncode public static List<string> specialCharactersNotAllowedInWindows = new List<string> { "/", "\\", "<", ">", ":", "\"", "|", "?", "*" //windows dissallowed character set }; public static string Encode(string fileName) { //CheckForFullPath(fileName); // optional: make sure it's not a path? List<string> charactersToChange = new List<string>(specialCharactersNotAllowedInWindows); charactersToChange.AddRange(urlEncodedCharacters. Where(x => !urlEncodedCharacters.Union(specialCharactersNotAllowedInWindows).Contains(x))); // add any non duplicates (%) charactersToChange.ForEach(s => fileName = fileName.Replace(s, Uri.HexEscape(s[0]))); // "?" => "%3f" return fileName; } 

谢谢@ simon-tewsi上面非常有用的表!

除了@丹·赫伯特的答案之外,你应该一般只对数值进行编码。

Split有params参数Split('&','='); expression式首先由&then'='分割,所以奇数元素是所有要编码的值,如下所示。

 public static void EncodeQueryString(ref string queryString) { var array=queryString.Split('&','='); for (int i = 0; i < array.Length; i++) { string part=array[i]; if(i%2==1) { part=System.Web.HttpUtility.UrlEncode(array[i]); queryString=queryString.Replace(array[i],part); } } } 

我写了一个C#方法,URL编码所有符号:

  /// <summary> /// !#$345Hf} → %21%23%24%33%34%35%48%66%7D /// </summary> public static string UrlEncodeExtended( string value ) { char[] chars = value.ToCharArray(); StringBuilder encodedValue = new StringBuilder(); foreach (char c in chars) { encodedValue.Append( "%" + ( (int)c ).ToString( "X2" ) ); } return encodedValue.ToString(); }