Jak zrobić UrlEncode bez korzystania z System.Web?

310

Usiłuję napisać aplikację kliencką dla systemu Windows, która wywołuje witrynę z danymi. Aby ograniczyć instalację do minimum, próbuję używać tylko bibliotek dll w profilu klienta .NET Framework . Problem w tym, że muszę UrlEncode niektórych parametrów. Czy istnieje prosty sposób, aby to zrobić bez importowania pliku System.Web.dll, który nie jest częścią pliku Pofile klienta?

Martin Brown
źródło
Czy możesz pokazać, w jaki sposób wykonujesz połączenie z witryną? Może jest coś, co można tam zrobić.
Darin Dimitrov
Z ciekawości, jak wywołać witrynę internetową dla danych bez korzystania z System.Web?
Patrick McDonald
@Pickick, prawdopodobnie używa WebRequestlub WebClient. To jest powód, dla którego zapytałem o ten konkretny kod, ponieważ są pewne rzeczy, które można zrobić w kwestii poprawnego kodowania danych URL.
Darin Dimitrov
1
Używam obiektu System.Net.WebRequest. Następnie wywołuję GetRequestStream i zapisuję parametry Post do strumienia. Ustawiłem także ContentType na „application / x-www-form-urlencoded”.
Martin Brown
1
Oczywiście to samo dotyczyłoby, gdybym wykonywał żądanie GET i dołączał parametry do adresu URL.
Martin Brown

Odpowiedzi:

317

System.Uri.EscapeUriString() może być problematyczne z niektórymi znakami, dla mnie był to znak liczby / funta „#” w ciągu.

Jeśli jest to dla Ciebie problem, spróbuj:

System.Uri.EscapeDataString() //Works excellent with individual values

Oto odpowiedź na pytanie SO, która wyjaśnia różnicę:

Jaka jest różnica między EscapeUriString i EscapeDataString?

i zaleca stosowanie Uri.EscapeDataString()w dowolnym aspekcie.

ToddBFisher
źródło
1
Fałsz: blogs.msdn.com/b/yangxind/archive/2006/11/09/… Będziesz mieć problemy ze znakami plus, ponieważ nie zostaną one zakodowane.
Chris Weber,
7
Ten post na blogu jest nieco stary i po prostu mam pełny adres URL „Uri Escaped”, a wszystkie spacje stały się% 20, więc myślę, że to naprawili. Używam .Net 4.5.
Rodi
EscapeDataString nie obsługuje również bardzo długich ciągów, jeśli przygotowujesz dane do operacji POST. stackoverflow.com/questions/6695208/...
Bron Davies,
Uri.EscapeUriStringjest rzeczywiście bardzo problematyczny i nie należy go stosować, ponieważ próbuje on zrobić coś (unikając pełnych identyfikatorów URI), co jest w rzeczywistości niemożliwe do konsekwentnego wykonania. Zobacz tę odpowiedź, aby uzyskać szczegółowe wyjaśnienie.
Livven,
Również postać spacji.
Waqas Shabbir
252

W użyciu .Net 4.5+ WebUtility

Tylko do sformatowania przesyłam to jako odpowiedź.

Nie udało mi się znaleźć dobrych przykładów porównujących je, więc:

string testString = "http://test# space 123/text?var=val&another=two";
Console.WriteLine("UrlEncode:         " + System.Web.HttpUtility.UrlEncode(testString));
Console.WriteLine("EscapeUriString:   " + Uri.EscapeUriString(testString));
Console.WriteLine("EscapeDataString:  " + Uri.EscapeDataString(testString));
Console.WriteLine("EscapeDataReplace: " + Uri.EscapeDataString(testString).Replace("%20", "+"));

Console.WriteLine("HtmlEncode:        " + System.Web.HttpUtility.HtmlEncode(testString));
Console.WriteLine("UrlPathEncode:     " + System.Web.HttpUtility.UrlPathEncode(testString));

//.Net 4.0+
Console.WriteLine("WebUtility.HtmlEncode: " + WebUtility.HtmlEncode(testString));
//.Net 4.5+
Console.WriteLine("WebUtility.UrlEncode:  " + WebUtility.UrlEncode(testString));

Wyjścia:

UrlEncode:             http%3a%2f%2ftest%23+space+123%2ftext%3fvar%3dval%26another%3dtwo
EscapeUriString:       http://test#%20space%20123/text?var=val&another=two
EscapeDataString:      http%3A%2F%2Ftest%23%20space%20123%2Ftext%3Fvar%3Dval%26another%3Dtwo
EscapeDataReplace:     http%3A%2F%2Ftest%23+space+123%2Ftext%3Fvar%3Dval%26another%3Dtwo

HtmlEncode:            http://test# space 123/text?var=val&another=two
UrlPathEncode:         http://test#%20space%20123/text?var=val&another=two

//.Net 4.0+
WebUtility.HtmlEncode: http://test# space 123/text?var=val&another=two
//.Net 4.5+
WebUtility.UrlEncode:  http%3A%2F%2Ftest%23+space+123%2Ftext%3Fvar%3Dval%26another%3Dtwo

W użyciu .Net 4.5+ WebUtility.UrlEncode

Wygląda na to, że replikuje się HttpUtility.UrlEncode(w wersjach wcześniejszych niż 4.0) w przypadku bardziej powszechnych znaków:
Uri.EscapeDataString(testString).Replace("%20", "+").Replace("'", "%27").Replace("~", "%7E")
Uwaga: EscapeUriStringzachowa prawidłowy ciąg znaków uri, co powoduje, że używa jak największej liczby znaków w postaci zwykłego tekstu.

Zobacz odpowiedź na tabelę porównującą różne kodowania:
https://stackoverflow.com/a/11236038/555798

Podziały linii Wszystkie wymienione tutaj (inne niż HttpUtility.HtmlEncode) zostaną zamienione "\n\r"na %0a%0dlub%0A%0D

Zmodyfikuj to i dodaj nowe znaki do mojego ciągu testowego lub zostaw je w komentarzach, a ja je wyedytuję.

Tymina
źródło
W moim przypadku musiałem użyć EscapeDataStringzamiast EscapeUriStringkodowania powrotów karetki i linii, a to wymagało bardziej agresywnego ucieczki, którego dokonałEscapeDataString
David O'Meara,
1
więcej przykładów, jeśli chcesz, możesz podać własne przypadki testowe. Oto próbka jego uruchomienia i innych metod kodowania, które pokazują różnice dotnetfiddle.net/12IFw1
Maslow
3
WebUtility.UrlEncode () i WebUtility.UrlDecode () to 4.5+. Nie istnieją w 4.0.
Derek Kalweit,
Msdn mówi: „Uniwersalna platforma Windows: dostępna od 4.5, .NET Framework: dostępna od 4.0” ...
Thymine
54

Możesz użyć

Uri.EscapeUriString (patrz http://msdn.microsoft.com/en-us/library/system.uri.escapeuristring.aspx )

Matthew Manela
źródło
Czy istnieje różnica między tym a EscapeDataString?
Martin Brown
3
Chcesz użyć EscapeUriString. EscapeUriString spróbuje zakodować cały adres URL (w tym http: // część), podczas gdy EscapeUriString zrozumie, które części powinny zostać zakodowane
Matthew Manela
1
Rozumiem, więc w tym przypadku prawdopodobnie chciałbym EscapeDataString, ponieważ mogę przekazać adres URL jako parametr get. W tym przypadku dołączam do adresu URL.
Martin Brown
5
@MatthewManela Jestem pewien, że Twój komentarz z października powinien brzmieć EscapeDataString spróbuje zakodować ...
Maslow
Nie używać Uri.EscapeUriString. Nie „rozumie”, jakie części należy zakodować, jest to po prostu błędna próba zrobienia czegoś (unikanie pełnych identyfikatorów URI), co w rzeczywistości jest niemożliwe do konsekwentnego wykonania. Zobacz tę odpowiedź, aby uzyskać szczegółowe wyjaśnienie.
Livven,
20

Odpowiedzi tutaj są bardzo dobre, ale wciąż dla mnie niewystarczające.

Napisałem małą pętlę, który porównuje Uri.EscapeUriStringsię Uri.EscapeDataStringdo wszystkich znaków od 0 do 255.

UWAGA: Obie funkcje mają wbudowaną inteligencję, że znaki powyżej 0x80 są najpierw kodowane UTF-8, a następnie procentowo.

Oto wynik:

******* Different *******

'#' -> Uri "#" Data "%23"
'$' -> Uri "$" Data "%24"
'&' -> Uri "&" Data "%26"
'+' -> Uri "+" Data "%2B"
',' -> Uri "," Data "%2C"
'/' -> Uri "/" Data "%2F"
':' -> Uri ":" Data "%3A"
';' -> Uri ";" Data "%3B"
'=' -> Uri "=" Data "%3D"
'?' -> Uri "?" Data "%3F"
'@' -> Uri "@" Data "%40"


******* Not escaped *******

'!' -> Uri "!" Data "!"
''' -> Uri "'" Data "'"
'(' -> Uri "(" Data "("
')' -> Uri ")" Data ")"
'*' -> Uri "*" Data "*"
'-' -> Uri "-" Data "-"
'.' -> Uri "." Data "."
'_' -> Uri "_" Data "_"
'~' -> Uri "~" Data "~"

'0' -> Uri "0" Data "0"
.....
'9' -> Uri "9" Data "9"

'A' -> Uri "A" Data "A"
......
'Z' -> Uri "Z" Data "Z"

'a' -> Uri "a" Data "a"
.....
'z' -> Uri "z" Data "z"

******* UTF 8 *******

.....
'Ò' -> Uri "%C3%92" Data "%C3%92"
'Ó' -> Uri "%C3%93" Data "%C3%93"
'Ô' -> Uri "%C3%94" Data "%C3%94"
'Õ' -> Uri "%C3%95" Data "%C3%95"
'Ö' -> Uri "%C3%96" Data "%C3%96"
.....

EscapeUriStringma być używany do kodowania adresów URL, podczas gdy EscapeDataStringma być używany do kodowania na przykład zawartości pliku cookie, ponieważ dane plików cookie nie mogą zawierać znaków zastrzeżonych '='i ';'.

Elmue
źródło
miła analiza i podział tutaj, bardzo pomocne. jeśli ktoś ma lub zna wzorce wydajności (porównując wszystkie trzy metody), również miło byłoby je zobaczyć
Shaun Wilson
To dobra analiza, a na wynos nie należy jej używać Uri.EscapeUriString, ponieważ unikanie pełnych identyfikatorów URI jest niemożliwe. Zobacz tę odpowiedź, aby uzyskać szczegółowe wyjaśnienie.
Livven,
16

Istnieje wersja użyteczna profilu klienta, klasa System.Net.WebUtility, obecna w profilu klienta System.dll. Oto link MSDN:

WebUtility

Sprague
źródło
Zwracam uwagę, że strona pomocy dla tej klasy wyraźnie mówi „Zapewnia metody kodowania i dekodowania adresów URL podczas przetwarzania żądań internetowych”. więc może być tak, że nie nazwali dobrze metod.
James White
Dobra uwaga, powiedz, dlaczego nie głosujesz na brata w górę;) ten głos w dół prześladuje mnie od 2 lat! JK ... ale szczerze mówiąc prawdopodobnie dlatego opublikowałem link, niefortunnie, że biorę reputację za błędy w dokumentach Microsoftu ...
Sprague
11
Wygląda na to, że UrlEncode i UrlDecode zostały dodane do WebUtility tylko w wersji 4.5 .Net.
Martin Brown
8

Oto przykład wysłania żądania POST, które poprawnie koduje parametry przy użyciu application/x-www-form-urlencodedtypu zawartości:

using (var client = new WebClient())
{
    var values = new NameValueCollection
    {
        { "param1", "value1" },
        { "param2", "value2" },
    };
    var result = client.UploadValues("http://foo.com", values);
}
Darin Dimitrov
źródło
-3
System.Net.WebUtility.HtmlDecode
użytkownik3105093
źródło
Klasa WebUtility zapewnia metody kodowania i dekodowania adresów URL podczas przetwarzania żądań internetowych. Robi to samo co HttpUtility, ale jest poza przestrzenią nazw System.Web
Alexandru Aliu
3
Jest źle, ponieważ kod HtmlDecodes i nie koduje UrlEncode jak zadane pytanie. Nawet HtmlEncode byłoby błędne, ponieważ kodowanie HTML różni się od kodowania URL.
Martin Brown