我有一个应用程序向VB论坛软件发送POST请求并记录某人(没有设置cookie或任何东西)。
一旦用户登录,我创建一个在其本地计算机上创建路径的变量。
C:\ tempfolder \日\用户名
问题是一些用户名正在抛出“非法字符”异常。例如,如果我的用户名是mas|fenix
,它会抛出异常..
Path.Combine( _
Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), _
DateTime.Now.ToString("ddMMyyhhmm") + "-" + form1.username)
我不想从字符串中删除它,但是在服务器上通过FTP创建了带有用户名的文件夹。这导致了我的第二个问题。如果我在服务器上创建一个文件夹,我可以留下“非法字符”吗?我只是问这个,因为服务器是基于Linux的,我不确定Linux是否接受它。
编辑:似乎URL编码不是我想要的..这是我想要做的:
old username = mas|fenix
new username = mas%xxfenix
其中%xx是ASCII值或任何其他可以轻松识别字符的值。
编辑:请注意,此答案现已过期。请参阅Siarhei Kuchuk's answer below以获得更好的解决方案
UrlEncoding将按照您的建议行事。使用C#,您只需使用HttpUtility
,如上所述。
你也可以正则表达非法字符,然后替换,但这要复杂得多,因为你必须有某种形式的状态机(例如switch ... case)来替换正确的字符。由于UrlEncode
预先做到这一点,所以很容易。
至于Linux与Windows,有一些在Linux中可以接受但不在Windows中的字符,但我不担心,因为可以通过使用UrlDecode
解码Url字符串来返回文件夹名称,所以你可以往返变化。
我编写了一个对所有符号进行url编码的C#方法:
/// <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();
}
理想情况下,这些将出现在名为“FileNaming”的类中,或者只是将Encode重命名为“FileNameEncode”。注意:这些不是为处理完整路径而设计的,只是处理文件夹和/或文件名。理想情况下,您首先拆分(“/”)完整路径,然后检查碎片。显然,不是联盟,你可以将“%”字符添加到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-lewis为上面非常有用的表格!
除了@Dan Herbert的回答,你我们应该只对这些值进行编码。
Split有params参数Split('&','=');表达式首先用&然后'='分割,所以奇数元素都是要编码的值,如下所示。
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);
}
}
}
我认为这里的人们被UrlEncode消息所牵制。 URLEncoding不是你想要的 - 你想编码那些在目标系统上不能用作文件名的东西。
假设你想要一些通用性 - 随意在几个系统(MacOS,Windows,Linux和Unix)上找到非法字符,将它们组合起来形成一组要逃脱的字符。
至于转义,HexEscape应该没问题(用%XX替换字符)。如果要支持不执行unicode的系统,请将每个字符转换为UTF-8字节并对所有内容进行编码> 128。但还有其他方法,例如使用反斜杠“\”或HTML编码“”“。您可以创建自己的。所有系统所要做的就是'编码'不兼容的字符。上述系统允许您重新创建原始名称 - 但是用空格替换坏字符也可以。
在与上面相同的切线上,唯一使用的是
Uri.EscapeDataString
- 它编码OAuth所需的所有内容,它不编码OAuth禁止编码的内容,并将空间编码为%20而不是+(也在OATH规范中)请参阅:RFC 3986.AFAIK,这是最新的URI规范。
我一直在尝试.NET为URL编码提供的各种方法。也许下面的表格很有用(作为我编写的测试应用程序的输出):
Unencoded UrlEncoded UrlEncodedUnicode UrlPathEncoded EscapedDataString EscapedUriString HtmlEncoded HtmlAttributeEncoded HexEscaped
A A A A A A A A %41
B B B B B B B B %42
a a a a a a a a %61
b b b b b b b b %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]
列表示编码如下:
HttpUtility.UrlEncode
HttpUtility.UrlEncodeUnicode
HttpUtility.UrlPathEncode
Uri.EscapeDataString
Uri.EscapeUriString
HttpUtility.HtmlEncode
HttpUtility.HtmlAttributeEncode
Uri.HexEscape
笔记:
HexEscape
只能处理前255个字符。因此,它会为拉丁语A-Extended字符(例如Â)抛出ArgumentOutOfRange
异常。编辑:
我添加了第二个表格,其中包含.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");
会屈服
Firewood%AA%F%Afoo.Google.com%OffArch %% Afaq%Admixbel
这显然不会很好。相反,您应该只编码查询字符串中键/值对的值,如下所示:
string url = "http://www.google.com/search?q=" + HttpUtility.UrlEncode("Example");
希望这会有所帮助。此外,正如teedyay所提到的,您仍然需要确保删除非法文件名字符,否则文件系统将不喜欢该路径。
从.NET Framework 4.5和.NET Standard 1.0开始,您应该使用WebUtility.UrlEncode
。优于替代品的优势:
HttpUtility
虽然早先在.NET Framework中可用(.NET Framework 1.1+),但在很久以后可以在其他平台上使用(.NET Core 2.0 +,.NET Standard 2.0+),它仍然无法在UWP中使用(请参阅related question)。System.dll
中,因此与HttpUtility
不同,它不需要任何其他引用。Uri.EscapeUriString
不同(请参阅comments to drweb86's answer)。Uri.EscapeDataString
(请参阅related question)不同,它对字符串的长度没有任何限制,因此它可以用于POST请求。Levi Botelho评论说,之前生成的编码表对于.NET 4.5不再准确,因为编码在.NET 4.0和4.5之间略有变化。所以我重新生成了.NET 4.5的表:
Unencoded UrlEncoded UrlEncodedUnicode UrlPathEncoded WebUtilityUrlEncoded EscapedDataString EscapedUriString HtmlEncoded HtmlAttributeEncoded WebUtilityHtmlEncoded HexEscaped
A A A A A A A A A A %41
B B B B B B B B B B %42
a a a a a a a a a a %61
b b b b b b b b b b %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]
列表示编码如下:
HttpUtility.UrlEncode
HttpUtility.UrlEncodeUnicode
HttpUtility.UrlPathEncode
WebUtility.UrlEncode
Uri.EscapeDataString
Uri.EscapeUriString
HttpUtility.HtmlEncode
HttpUtility.HtmlAttributeEncode
WebUtility.HtmlEncode
Uri.HexEscape
笔记:
编辑:
在.NET中,URL编码很容易。使用:
System.Web.HttpUtility.UrlEncode(string url)
如果要对其进行解码以获取文件夹名称,则仍需要排除不能在文件夹名称中使用的字符(*,?,/等)
如果看不到System.Web,请更改项目设置。目标框架应该是“.NET Framework 4”而不是“.NET Framework 4 Client Profile”
UrlEncode
的.NET实现不符合RFC 3986。
!()*
字符在RFC的2.2节中列为必须编码的保留字符,但.NET无法对这些字符进行编码。.-_
字符未在RFC的2.2节中列为不应编码的保留字符,但.NET错误地编码这些字符。