¿Cuál es la diferencia entre EscapeUriString y EscapeDataString?

192

Si solo trata con la codificación url, ¿debería usar EscapeUriString ?

user496949
fuente
10
Siempre escape de cada valor individual utilizando Uri.EscapeDataString(), como se explica en la respuesta de @ Livven. Con otros enfoques, el sistema simplemente no tiene suficiente información para producir el resultado previsto para cada entrada posible.
Timo

Respuestas:

112

Úselo EscapeDataStringsiempre (para obtener más información sobre por qué, consulte la respuesta de Livven a continuación)

Editar : se eliminó el enlace muerto sobre cómo difieren los dos en la codificación

Jcl
fuente
3
No estoy seguro de que ese enlace en realidad proporcione más información, ya que se trata de la eliminación de escapes en lugar de esa eliminación.
Steven
1
Básicamente es la misma diferencia. Si realmente lees el artículo, hay una tabla en el medio que realmente se escapa (no sin paisajes) para mostrar las diferencias (en comparación con URLEncode).
Jcl
2
Todavía no me queda claro, ¿qué pasa si no escapo de un URI completo sino solo de una parte de él (es decir, los datos para un parámetro de cadena de consulta)? ¿Estoy escapando datos para el URI, o EscapeDataString implica algo completamente diferente?
BrainSlugs83
44
... algunas pruebas parecen querer EscapeDataString para un parámetro URI. Probé con la cadena "I heart C ++" y EscapeUriString no codificó los caracteres "+", simplemente los dejó como están, EscapeDataString los convirtió correctamente a "% 2B".
BrainSlugs83
77
Esta es una mala respuesta. Nunca debe usar EscapeUriString, no tiene ningún sentido. Ver la respuesta de Livven a continuación (y votarla).
Brandon Paddock
242

No encontré las respuestas existentes satisfactorias, así que decidí profundizar un poco más para resolver este problema. Sorprendentemente, la respuesta es muy simple:

No hay (casi *) ninguna razón válida para usarla Uri.EscapeUriString. Si necesita codificar en porcentaje una cadena, use siempre Uri.EscapeDataString.

* Vea el último párrafo para un caso de uso válido.

¿Por qué es esto? De acuerdo con la documentación :

Use el método EscapeUriString para preparar una cadena de URI sin escape para que sea un parámetro para el constructor de Uri.

Esto realmente no tiene sentido. De acuerdo con RFC 2396 :

Un URI siempre está en forma de "escape", ya que escapar o escapar de un URI completo podría cambiar su semántica.

Si bien el RFC citado ha quedado obsoleto por RFC 3986 , el punto sigue en pie. Vamos a verificarlo mirando algunos ejemplos concretos:

  1. Tienes un URI simple, como este:

    http://example.org/

    Uri.EscapeUriString No lo cambiará.

  2. Decide editar manualmente la cadena de consulta sin tener en cuenta el escape:

    http://example.org/?key=two words

    Uri.EscapeUriString (correctamente) escapará del espacio por ti:

    http://example.org/?key=two%20words
  3. Decide editar manualmente la cadena de consulta aún más:

    http://example.org/?parameter=father&son

    Sin embargo, esta cadena no cambia Uri.EscapeUriString, ya que asume el ampers y significa el inicio de otro par clave-valor. Esto puede o no ser lo que pretendía.

  4. Decide que, de hecho, desea que sea el keyparámetro father&son, por lo que arregla la URL anterior manualmente escapando del signo y:

    http://example.org/?parameter=father%26son

    Sin embargo, Uri.EscapeUriStringtambién escapará al carácter de porcentaje, lo que conducirá a una doble codificación:

    http://example.org/?parameter=father%2526son

Como puede ver, el uso Uri.EscapeUriStringpara su propósito previsto hace que sea imposible usarlo &como parte de una clave o valor en una cadena de consulta en lugar de como un separador entre múltiples pares clave-valor.

Esto se debe a que, en un intento de hacerlo adecuado para escapar de los URI completos, ignora los caracteres reservados y solo escapa a los caracteres que no están reservados ni no reservados, lo que, por cierto, es contrario a la documentación . De esta manera, no terminas con algo como esto http%3A%2F%2Fexample.org%2F, pero sí terminas con los problemas ilustrados anteriormente.


Al final, si su URI es válido, no necesita escapar para pasarlo como un parámetro al constructor de Uri, y si no es válido, llamar Uri.EscapeUriStringtampoco es una solución mágica. En realidad, funcionará en muchos, si no en la mayoría de los casos, pero de ninguna manera es confiable.

Siempre debe construir sus URL y cadenas de consulta reuniendo los pares clave-valor y la codificación porcentual y luego concatenándolos con los separadores necesarios. Puede usar Uri.EscapeDataStringpara este propósito, pero no Uri.EscapeUriString, ya que no escapa a los caracteres reservados, como se mencionó anteriormente.

Solo si no puede hacerlo, por ejemplo, cuando se trata de URI proporcionados por el usuario, tiene sentido usarlo Uri.EscapeUriStringcomo último recurso. Pero se aplican las advertencias mencionadas anteriormente: si el URI proporcionado por el usuario es ambiguo, los resultados pueden no ser deseables.

Livven
fuente
44
Wow, gracias por finalmente aclarar este problema. Las dos respuestas anteriores no fueron muy útiles.
EverPresent
3
Exactamente correcto. EscapeUriString (como el comportamiento predeterminado de EscapeUrl en Win32) fue creado por alguien que no entendió los URI o escapó. Es un intento equivocado de crear algo que tenga un URI malformado y, a veces, convertirlo en la versión deseada. Pero no tiene la información que necesita para hacer esto de manera confiable. También se usa con frecuencia en lugar de EscapeDataString, que también es muy problemático. Desearía que EscapeUriString no existiera. Cada uso es incorrecto.
Brandon Paddock
44
Bien explicado +1 es mucho mejor que el enlace aceptado solo respuesta
Ehsan Sajjad
1
Esta respuesta necesita más atención. Es la forma correcta de hacerlo. Las otras respuestas tienen escenarios en los que no producen los resultados previstos.
Timo
1
... Claro encodeURI/ Uri.EscapeUriStringno se necesita con tanta frecuencia como encodeURIComponent/ Uri.EscapeDataString(ya que cuando se trata de url ciegos que deben usarse en un contexto uri), pero eso no significa que no tenga su lugar.
Crescent Fresh
56

Los caracteres más (+) pueden revelar mucho sobre la diferencia entre estos métodos. En un URI simple, el carácter más significa "espacio". Considere consultar a Google para "gato feliz":

https://www.google.com/?q=happy+cat

Es un URI válido (pruébelo) y EscapeUriStringno lo modificará.

Ahora considere consultar en Google "happy c ++":

https://www.google.com/?q=happy+c++

Es un URI válido (pruébelo), pero produce una búsqueda de "happy c", porque las dos ventajas se interpretan como espacios. Para solucionarlo, podemos pasar "happy c ++" a EscapeDataStringy voila * :

https://www.google.com/?q=happy+c%2B%2B

*) La cadena de datos codificada es en realidad "feliz% 20c% 2B% 2B"; % 20 es hexadecimal para el carácter de espacio, y% 2B es hexadecimal para el carácter más.

Si está utilizando UriBuildercomo debería, entonces solo necesitará EscapeDataStringescapar adecuadamente de algunos de los componentes de su URI completo. La respuesta de @ Livven a esta pregunta demuestra que realmente no hay razón para usar EscapeUriString.

Seth
fuente
Gracias. ¿Qué pasa cuando tiene una cadena de URI absoluta que necesita codificar, por ejemplo "https://www.google.com/?q=happy c++"? Parece que necesito dividirme manualmente en "?", ¿O hay una mejor manera?
wensveen
Si está pasando la URL completa como parámetro a otra URL, entonces úsela EscapeDataString. Si la URL que proporcionó es la URL real, entonces sí desea dividirla ?.
Seth
7

Los comentarios en la fuente abordan la diferencia claramente. Por qué esta información no se presenta a través de comentarios de documentación XML es un misterio para mí.

EscapeUriString:

Este método escapará a cualquier carácter que no sea un carácter reservado o no reservado, incluidos los signos de porcentaje. Tenga en cuenta que EscapeUriString tampoco escapará a un signo '#'.

EscapeDataString:

Este método escapará a cualquier carácter que no sea un carácter no reservado, incluidos los signos de porcentaje.

Entonces, la diferencia está en cómo manejan los caracteres reservados . EscapeDataStringse les escapa; EscapeUriStringno.

Según la RFC , los caracteres reservados son::/?#[]@!$&'()*+,;=

Para completar, los caracteres no reservados son alfanuméricos y -._~

Ambos métodos escapan caracteres que no están reservados ni no reservados.

No estoy de acuerdo con la noción general de que EscapeUriStringes malo. Creo que un método que escapa solo de caracteres ilegales (como espacios) y no caracteres reservados es útil. Pero tiene una peculiaridad en cómo maneja al %personaje. Los caracteres codificados en porcentaje ( %seguidos de 2 dígitos hexadecimales) son legales en un URI. Creo que EscapeUriStringsería mucho más útil si detectara este patrón y evitara la codificación %cuando proceda inmediatamente con 2 dígitos hexadecimales.

Todd Menier
fuente
1

Un simple ejemplo

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
*/
Aprendizaje
fuente