Jeśli tylko zajmujesz się kodowaniem adresów URL, powinienem użyć EscapeUriString ?
Jeśli tylko zajmujesz się kodowaniem adresów URL, powinienem użyć EscapeUriString ?
Odpowiedzi:
Używaj EscapeDataString
zawsze (więcej informacji na temat przyczyny znajduje się poniżej w odpowiedzi Livven )
Edycja : usunięto martwy link do różnic między kodowaniem
URLEncode
).
Nie uznałem istniejących odpowiedzi za zadowalające, więc postanowiłem głębiej zbadać ten problem. Co zaskakujące, odpowiedź jest bardzo prosta:
Nie ma (prawie *) żadnego ważnego powodu, aby kiedykolwiek używać Uri.EscapeUriString
. Jeśli potrzebujesz procentowo zakodować ciąg, zawsze używaj Uri.EscapeDataString
.
* Patrz ostatni akapit dla ważnego przypadku użycia.
Dlaczego to? Zgodnie z dokumentacją :
Użyj metody EscapeUriString, aby przygotować nieskalowany ciąg URI, który będzie parametrem dla konstruktora Uri.
To naprawdę nie ma sensu. Zgodnie z RFC 2396 :
Identyfikator URI jest zawsze w formie „ucieczki”, ponieważ ucieczka lub odblokowanie ukończonego URI może zmienić jego semantykę.
Chociaż cytowany RFC został zdezaktualizowany przez RFC 3986 , kwestia nadal jest ważna. Sprawdźmy to, patrząc na konkretne przykłady:
Masz prosty identyfikator URI, taki jak ten:
http://example.org/
Uri.EscapeUriString
nie zmieni tego.
Zdecydujesz się ręcznie edytować ciąg zapytania bez uwzględnienia zmiany znaczenia:
http://example.org/?key=two words
Uri.EscapeUriString
(poprawnie) wydostanie się z miejsca dla ciebie:
http://example.org/?key=two%20words
Zdecydujesz się ręcznie edytować ciąg zapytania jeszcze dalej:
http://example.org/?parameter=father&son
Jednak ten ciąg nie jest zmieniany przez Uri.EscapeUriString
, ponieważ zakłada, że ampersand oznacza początek innej pary klucz-wartość. To może, ale nie musi być to, co zamierzałeś.
Decydujesz, że tak naprawdę chcesz, aby key
parametr był father&son
, więc naprawiasz poprzedni adres URL ręcznie, usuwając znak ampersand:
http://example.org/?parameter=father%26son
Jednak Uri.EscapeUriString
ucieknie również od znaku procentu, co prowadzi do podwójnego kodowania:
http://example.org/?parameter=father%2526son
Jak widać, użycie Uri.EscapeUriString
zgodnie z przeznaczeniem uniemożliwia użycie &
jako części klucza lub wartości w ciągu zapytania zamiast jako separatora między wieloma parami klucz-wartość.
Wynika to z tego, że próbując uczynić go odpowiednim do ucieczki pełnych identyfikatorów URI, ignoruje znaki zarezerwowane i unika tylko znaków, które nie są zastrzeżone ani niezarezerwowane, co BTW jest sprzeczne z dokumentacją . W ten sposób nie kończy się coś takiego http%3A%2F%2Fexample.org%2F
, ale kończy się to przedstawionymi powyżej problemami.
Ostatecznie, jeśli twój identyfikator URI jest prawidłowy, nie musi być poprzedzany znakiem ucieczki, aby mógł zostać przekazany jako parametr do konstruktora Uri, a jeśli nie jest prawidłowy, wywołanie również Uri.EscapeUriString
nie jest magicznym rozwiązaniem. W rzeczywistości będzie działać w wielu, jeśli nie w większości przypadków, ale w żadnym wypadku nie jest niezawodny.
Zawsze należy konstruować adresy URL i ciągi zapytań, gromadząc pary klucz-wartość i kodowanie procentowe, a następnie łącząc je z niezbędnymi separatorami. Możesz użyć Uri.EscapeDataString
do tego celu, ale nie Uri.EscapeUriString
, ponieważ nie ucieka on od zarezerwowanych znaków, jak wspomniano powyżej.
Tylko wtedy, gdy nie możesz tego zrobić, np. W przypadku identyfikatorów URI podanych przez użytkownika, ma sens zastosowanie Uri.EscapeUriString
w ostateczności. Obowiązują jednak wspomniane wcześniej zastrzeżenia - jeśli podany przez użytkownika identyfikator URI jest niejednoznaczny, wyniki mogą być niepożądane.
encodeURI
/ Uri.EscapeUriString
nie jest potrzebny tak często jak encodeURIComponent
/ Uri.EscapeDataString
(od kiedy masz do czynienia z ślepymi adresami URL, które muszą być używane w kontekście URI), ale to nie znaczy, że nie ma swojego miejsca.
Znaki plus (+) mogą wiele powiedzieć o różnicy między tymi metodami. W prostym URI znak plus oznacza „spację”. Rozważ zapytanie do Google o „szczęśliwego kota”:
To prawidłowy identyfikator URI (spróbuj) i EscapeUriString
nie będzie go modyfikować.
Teraz rozważ zapytanie Google o „happy c ++”:
To jest poprawny URI (spróbuj), ale powoduje wyszukiwanie „szczęśliwego c”, ponieważ dwie plusy są interpretowane jako spacje. Aby to naprawić, możemy przekazać „happy c ++” do EscapeDataString
i voila * :
*) Zakodowany ciąg danych to tak naprawdę „happy% 20c% 2B% 2B”; % 20 to hex dla znaku spacji, a% 2B to hex dla znaku plus.
Jeśli używasz tego, UriBuilder
co powinieneś, musisz EscapeDataString
właściwie uciec tylko niektórych składników całego identyfikatora URI. Odpowiedź @ Livven na to pytanie dalej dowodzi, że tak naprawdę nie ma powodu, aby z tego korzystać EscapeUriString
.
"https://www.google.com/?q=happy c++"
. Wygląda na to, że muszę ręcznie podzielić na „?”, Czy jest lepszy sposób?
EscapeDataString
. Jeśli podany adres URL jest rzeczywistym adresem URL, to tak, po prostu chcesz się podzielić ?
.
Komentarze w źródle wyraźnie odnoszą się do różnicy. Dlaczego te informacje nie są przekazywane za pośrednictwem komentarzy do dokumentacji XML, jest dla mnie zagadką.
EscapeUriString:
Ta metoda pozwoli uniknąć dowolnego znaku, który nie jest znakiem zastrzeżonym lub niezarezerwowanym, w tym znaków procentu. Pamiętaj, że EscapeUriString również nie uniknie znaku „#”.
EscapeDataString:
Ta metoda pozwoli uniknąć dowolnego znaku, który nie jest znakiem bez zastrzeżeń, w tym znaków procentu.
Różnica polega na tym, jak radzą sobie z zastrzeżonymi znakami. EscapeDataString
ucieka im; EscapeUriString
nie.
Zgodnie z RFC zarezerwowanymi znakami są::/?#[]@!$&'()*+,;=
Dla kompletności, niezarezerwowane znaki są alfanumeryczne i -._~
Obie metody unikają znaków, które nie są ani zarezerwowane, ani zastrzeżone.
Nie zgadzam się z ogólnym pojęciem, które EscapeUriString
jest złe. Myślę, że metoda, która pozwala na uniknięcie tylko niedozwolonych znaków (takich jak spacje) i niezastrzeżonych znaków, jest przydatna. Ale ma dziwactwo w tym, jak radzi sobie z %
postacią. Znaki zakodowane w procentach ( %
po których następują 2 cyfry szesnastkowe) są poprawne w URI. Myślę, że EscapeUriString
byłoby znacznie bardziej przydatne, gdyby wykrył ten wzorzec i uniknął kodowania, %
gdy natychmiast poprzedzają go 2 cyfry szesnastkowe.
Prosty przykład
var data = "example.com/abc?DEF=あいう\x20えお";
Console.WriteLine(Uri.EscapeUriString(data));
Console.WriteLine(Uri.EscapeDataString(data));
Console.WriteLine(System.Net.WebUtility.UrlEncode(data));
Console.WriteLine(System.Web.HttpUtility.UrlEncode(data));
/*
=>
example.com/abc?DEF=%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86+%E3%81%88%E3%81%8A
example.com%2fabc%3fDEF%3d%e3%81%82%e3%81%84%e3%81%86+%e3%81%88%e3%81%8a
*/
Uri.EscapeDataString()
, jak wyjaśniono w odpowiedzi @ Livven. W przypadku innych podejść system po prostu nie ma wystarczających informacji, aby uzyskać zamierzony wynik dla każdego możliwego wkładu.