Server.UrlEncode vs. HttpUtility.UrlEncode

C’è una differenza tra Server.UrlEncode e HttpUtility.UrlEncode?

HttpServerUtility.UrlEncode utilizzerà HttpUtility.UrlEncode internamente. Non c’è alcuna differenza specifica. Il motivo dell’esistenza di Server.UrlEncode è la compatibilità con ASP classico.

Prima ho avuto grattacapi significativi con questi metodi, ti consiglio di evitare qualsiasi variante di UrlEncode , e invece di usare Uri.EscapeDataString – almeno quello ha un comportamento comprensibile.

Vediamo…

 HttpUtility.UrlEncode(" ") == "+" //breaks ASP.NET when used in paths, non- //standard, undocumented. Uri.EscapeUriString("a?b=e") == "a?b=e" // makes sense, but rarely what you // want, since you still need to // escape special characters yourself 

Ma il mio preferito personale deve essere HttpUtility.UrlPathEncode – questa cosa è davvero incomprensibile. Codifica:

  • “” ==> “% 20”
  • “100% true” ==> “100 %% 20true” (ok, il tuo url è rotto ora)
  • “test A.aspx # anchor B” ==> “test% 20A.aspx # anchor% 20B
  • “test A.aspx? hmm # anchor B” ==> “test% 20A.aspx? hmm #anchor B ” ( notare la differenza con la precedente sequenza di escape! )

Ha anche la documentazione MSDN molto bella “Codifica la porzione di percorso di una stringa URL per una trasmissione HTTP affidabile dal server Web a un client.” – senza effettivamente spiegare cosa fa. Hai meno probabilità di spararti ai piedi con un Uzi …

In breve, attenersi a Uri.EscapeDataString .

Tieni presente che probabilmente non dovresti utilizzare nessuno dei due metodi. La libreria di scripting del sito anti-cross di Microsoft include sostituzioni per HttpUtility.UrlEncode e HttpUtility.HtmlEncode che sono più conformi agli standard e più sicure. Come bonus, ottieni anche un metodo JavaScriptEncode .

Avanti di quasi 9 anni da quando è stato chiesto per la prima volta, e nel mondo di .NET Core e .NET Standard, sembra che le opzioni più comuni che abbiamo per la codifica dell’URL siano WebUtility.UrlEncode (in System.Net ) e Uri. EscapeDataString . A giudicare dalla risposta più popolare qui e altrove, Uri.EscapeDataString sembra essere preferibile. Ma è così? Ho fatto alcune analisi per capire le differenze ed ecco cosa mi è venuto in mente:

  • WebUtility.UrlEncode codifica lo spazio come + ; Uri.EscapeDataString codifica come %20 .
  • Uri.EscapeDataString percent-encodes ! , ( , ) e * ; WebUtility.UrlEncode no.
  • WebUtility.UrlEncode percent-encodes ~ ; Uri.EscapeDataString no.
  • Uri.EscapeDataString genera una UriFormatException su stringhe di lunghezza superiore a 65.520 caratteri; WebUtility.UrlEncode no. ( Un problema più comune di quanto si possa pensare, in particolare quando si tratta di dati di moduli con codifica URL ).
  • Uri.EscapeDataString genera una UriFormatException sugli alti caratteri surrogati ; WebUtility.UrlEncode no. (Questa è una cosa UTF-16, probabilmente molto meno comune.)

Ai fini della codifica dell’URL, i caratteri rientrano in una delle 3 categorie: senza riserva (legale in un URL); riservato (legale ma ha un significato speciale, quindi potresti volerlo codificare); e tutto il resto (deve sempre essere codificato).

Secondo la RFC , i caratteri riservati sono:: :/?#[]@!$&'()*+,;=

E i caratteri non riservati sono alfanumerici e -._~

Il verdetto

Uri.EscapeDataString definisce chiaramente la sua missione:% -encode tutti i caratteri riservati e illegali. WebUtility.UrlEncode è più ambiguo sia nella definizione che nell’implementazione. Stranamente, codifica alcuni caratteri riservati ma non altri (perché parentesi e non parentesi ??), e stranamente ancora codifica quel carattere innocentemente senza riserve.

Pertanto, concordo con il consiglio più diffuso: utilizzare Uri.EscapeDataString quando ansible e capire che i caratteri riservati sono / come ? sarà codificato. Se è necessario gestire stringhe potenzialmente di grandi dimensioni, in particolare con i contenuti dei moduli con codifica URL, è necessario ricorrere a WebUtility.UrlEncode e accettarne le stranezze o comunque aggirare il problema.


EDIT: Ho tentato di correggere TUTTE le stranezze sopra menzionate in Flurl tramite i metodi statici Url.Encode , Url.EncodeIllegalCharacters e Url.Decode . Questi sono nel pacchetto principale (che è piccolo e non include tutte le informazioni HTTP), o si sentono liberi di estrarli dalla fonte. Accolgo con favore eventuali commenti / feedback su questi.


Ecco il codice che ho usato per scoprire quali caratteri sono codificati in modo diverso:

 var diffs = from i in Enumerable.Range(0, char.MaxValue + 1) let c = (char)i where !char.IsHighSurrogate(c) let diff = new { Original = c, UrlEncode = WebUtility.UrlEncode(c.ToString()), EscapeDataString = Uri.EscapeDataString(c.ToString()), } where diff.UrlEncode != diff.EscapeDataString select diff; foreach (var diff in diffs) Console.WriteLine($"{diff.Original}\t{diff.UrlEncode}\t{diff.EscapeDataString}"); 

Server.UrlEncode () è lì per fornire la retrocompatibilità con Classic ASP,

 Server.UrlEncode(str); 

È equivalente a:

 HttpUtility.UrlEncode(str, Response.ContentEncoding); 

Lo stesso, Server.UrlEncode() chiama HttpUtility.UrlEncode()