Кодирование URL с использованием С#
У меня есть приложение, которое отправляет запрос POST на программное обеспечение форума VB и регистрирует кого-либо (без установки файлов 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 или любое другое значение, которое легко идентифицирует символ.
Ответы
Ответ 1
Изменить: обратите внимание, что этот ответ устарел. См. Ответ Сергея Кучука ниже для лучшего исправления
UrlEncoding будет делать то, что вы предлагаете здесь. С С# вы просто используете HttpUtility
, как уже упоминалось.
Вы также можете повторно использовать недопустимые символы, а затем заменять, но это становится намного сложнее, так как вам нужно будет иметь некоторую форму конечного автомата (например, для случая), чтобы заменить правильные символы. Поскольку UrlEncode
делает это спереди, это довольно просто.
Что касается Linux в сравнении с окнами, в Linux есть некоторые символы, которые не подходят в Windows, но я бы не стал беспокоиться об этом, так как имя папки можно вернуть, расшифровав строку Url, используя UrlDecode
, поэтому вы можете обойти изменения.
Ответ 2
Я экспериментировал с различными методами .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]
Колонки представляют кодировки следующим образом:
-
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 символов. Поэтому он генерирует исключение ArgumentOutOfRange
для символов Latin A-Extended (например, Ā).
-
Эта таблица была сгенерирована в .NET 4.0 (см. комментарий Levi Botelho ниже, в котором говорится, что кодировка в .NET 4.5 немного отличается).
EDIT:
Я добавил вторую таблицу с кодировками для .NET 4.5. См. Этот ответ: fooobar.com/questions/8420/...
ИЗМЕНИТЬ 2:
Поскольку люди, похоже, ценят эти таблицы, я думал, что вам может понравиться исходный код, который генерирует таблицу, поэтому вы можете играть вокруг себя. Это простое консольное приложение С#, которое может быть нацелено на .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" + " !\"#$%&'()*+,-./:;<=>[email protected][\\]^_`{|}~" + "ĀāĒēĪīŌōŪū";
// 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();
}
}
}
}
Ответ 3
Вы должны кодировать только имя пользователя или другую часть URL-адреса, которая может быть недействительной. URL-кодирование URL-адреса может привести к проблемам, так как примерно следующее:
string url = HttpUtility.UrlEncode("http://www.google.com/search?q=Example");
Уступит
HTTP% 3a% 2f% 2fwww.google.com% 2fsearch% 3fq% 3dExample
Это, очевидно, не будет работать хорошо. Вместо этого вы должны кодировать ТОЛЬКО значение пары ключ/значение в строке запроса, например:
string url = "http://www.google.com/search?q=" + HttpUtility.UrlEncode("Example");
Надеюсь, это поможет. Кроме того, как упоминалось teedyay, вам все равно нужно убедиться, что незаконные имена имен файлов удалены, иначе файловая система не понравится путь.
Ответ 4
Лучше использовать
Uri.EscapeUriString
не ссылаться на полный профиль .net 4.
Ответ 5
С .NET Framework 4.5 вы можете использовать WebUtility.UrlEncode
.
Во-первых, он находится в System.dll
, поэтому он не требует дополнительных ссылок.
Во-вторых, он правильно экранирует символы для URL-адресов, в отличие от Uri.EscapeUriString
(см. комментарии к ответу drweb86).
В-третьих, он не имеет ограничений по длине строки, в отличие от Uri.EscapeDataString
(см. связанный вопрос), поэтому его можно использовать для запросов POST, например.
В-четвертых, он доступен в WinRT, в отличие от HttpUtility
(см. связанный вопрос).
Ответ 6
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]
Колонки представляют кодировки следующим образом:
- 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 символов. Поэтому он генерирует исключение ArgumentOutOfRange для латинских символов A-Extended (например, Ā).
-
Эта таблица была сгенерирована в .NET 4.5 (см. ответ fooobar.com/questions/8420/... для кодировок, относящихся к .NET 4.0 и ниже).
EDIT:
- В результате ответа Discord я добавил новые методы WebUtility UrlEncode и HtmlEncode, которые были представлены в .NET 4.5.
Ответ 7
Кодирование URL легко в .NET. Использование:
System.Web.HttpUtility.UrlEncode(string url)
Если это будет расшифровано, чтобы получить имя папки, вам все равно нужно исключить символы, которые нельзя использовать в именах папок (*,?,/и т.д.)
Ответ 8
Если вы не видите System.Web, измените настройки своего проекта. Целевая структура должна быть ".NET Framework 4" вместо ".NET Framework 4 Client Profile"
Ответ 9
Реализация .NET UrlEncode
.NET не соответствует RFC 3986.
-
Некоторые символы не кодируются, но должны быть. Символы !()*
перечислены в разделе 2.2 RFC как зарезервированные символы, которые должны быть закодированы, но .NET не может кодировать эти символы.
-
Некоторые символы кодируются, но не должны быть. Символы .-_
не указаны в RFC-разделе 2.2 в качестве зарезервированного символа, который не должен кодироваться, но .NET ошибочно кодирует эти символы.
-
RFC указывает, что для согласования реализация должна использовать HSEDIG с верхним регистром, где .NET создает нижний регистр HEXDIG.
Ответ 10
В идеале они будут проходить в классе под названием "FileNaming" или просто переименовать Encode в "FileNameEncode". Примечание. Они не предназначены для обработки полных путей, а только для имени папки и/или имени файла. В идеале вы сначала разделите ( "/" ) свой полный путь, а затем проверите части.
И, очевидно, вместо объединения вы можете просто добавить символ "%" в список символов, которые не разрешены в Windows, но я думаю, что это более полезно/удобочитаемо/фактически так.
Decode() - это точно то же самое, но переключает Replace (Uri.HexEscape(s [0]), s) "escaped" с символом.
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 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 за очень полезную таблицу выше!
Ответ 11
Я написал метод С#, который 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();
}
Ответ 12
В дополнение к ответу @Dan Herbert,
Вы должны кодировать только значения в целом.
Сплит имеет параметр param 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);
}
}
}
Ответ 13
Я думаю, что люди здесь отвлеклись на сообщение UrlEncode. URLEncoding - это не то, что вам нужно - вы хотите кодировать вещи, которые не будут работать в качестве имени файла в целевой системе.
Предполагая, что вам нужна некоторая универсальность - не стесняйтесь находить недопустимые символы в нескольких системах (MacOS, Windows, Linux и Unix), объединяйте их, чтобы сформировать набор символов, чтобы избежать.
Что касается побега, HexEscape должен быть в порядке (замена символов на% XX). Преобразуйте каждый символ в байты UTF-8 и закодируйте все> 128, если вы хотите поддерживать системы, которые не поддерживают Unicode. Но есть и другие способы, такие как использование обратной косой черты "\" или HTML-кодировка "" ". Вы можете создать свой собственный. Все, что нужно сделать системе - это" кодировать "несовместимый символ. Вышеуказанные системы позволяют воссоздать оригинальное имя - но что-то вроде замены плохих символов пробелами тоже работает.
На той же касательной, что и выше, используется только один
Uri.EscapeDataString
- Он кодирует все, что нужно для OAuth, он не кодирует вещи, которые OAuth запрещает кодирование, и кодирует пространство как %20, а не + (также в спецификации OATH). См.: RFC 3986. AFAIK, это последняя спецификация URI.