使用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 " " %22 # %23 %23 # %23 # # # %23 $ %24 %24 $ %24 $ $ $ %24 % %25 %25 % %25 %25 % % %25 & %26 %26 & %26 & & & %26 ' %27 %27 ' ' ' ' ' %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 < < %3C = %3d %3d = %3D = = = %3D > %3e %3e > %3E %3E > > %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
笔记:
-
HexEscape
只能处理前255个字符。 因此它为拉丁A扩展字符(例如Â)抛出一个ArgumentOutOfRange
exception。 -
这个表是在.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 " " " %22 # %23 %23 # %23 %23 # # # # %23 $ %24 %24 $ %24 %24 $ $ $ $ %24 % %25 %25 % %25 %25 %25 % % % %25 & %26 %26 & %26 %26 & & & & %26 ' %27 %27 ' %27 %27 ' ' ' ' %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 < < < %3C = %3d %3d = %3D %3D = = = = %3D > %3e %3e > %3E %3E %3E > > > %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
笔记:
-
HexEscape只能处理前255个字符。 因此它为拉丁A扩展字符(例如Â)抛出一个ArgumentOutOfRangeexception。
-
该表是在.NET 4.5中生成的(请参阅https://stackoverflow.com/a/11236038/216440 ,了解与.NET 4.0及以下版本相关的编码)。
编辑:
- 由于Discord的回答,我添加了.NET 4.5中引入的新的WebUtility UrlEncode和HtmlEncode方法。
如果您看不到System.Web,请更改您的项目设置。 目标框架应该是“.NET Framework 4”而不是“.NET Framework 4 Client Profile”
UrlEncode
的.NET实现不符合RFC 3986。
-
有些字符不是编码,但应该是。
!()*
字符在RFC的第2.2节中列出为必须编码的保留字符,但.NET无法对这些字符进行编码。 -
一些字符被编码,但不应该是。
.-_
字符在RFC的第2.2节中没有列为保留字符,不应该被编码,但.NET错误地编码了这些字符。 -
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(); }
- 强制XmlSerializer将“DateTime”序列化为“YYYY-MM-DD hh:mm:ss”
- 将接收到的对象转换为List <object>或IEnumerable <object>
- 带默认命名空间的Xml-SelectNodes通过XmlNamespaceManager不能正常工作
- HTML.ActionLink方法
- 命名空间clr-namespace <…>中不存在名称<…>
- Properties.Settings.Default在哪里存储?
- 在WPF中,x:Name和Name属性有什么区别?
- .NET的HashTable Vs字典 – 字典可以一样快吗?
- Parallel.ForEach块吗?