2010-02-08 9 views
12

He estado rastreando un error en una aplicación de reescritura de Url. El error apareció como un problema de codificación en algunos caracteres diacríticos en la cadena de consulta.¿Cuál es la diferencia entre Request.Url.Query y Request.QueryString?

Básicamente, el problema era que una solicitud que era básicamente /search.aspx?search=heřmánek estaba siendo reescrito con una cadena de consulta de "búsqueda = él% c5% 99m% c3% a1nek"

El valor correcto (usando un código de trabajo diferente) fue una reescritura de la cadena de consulta como "search = he% u0159m% u00e1nek"

Tenga en cuenta la diferencia entre las dos cadenas. Sin embargo, si publica ambos, verá que la Codificación de URL reproduce la misma cadena. No es hasta que use el contexto. Reescribir la función que rompe la codificación. La cadena rota devuelve 'heÅmánek' (usando Request.QueryString ["Search"] y la cadena de trabajo devuelve 'heřmánek'. Este cambio ocurre después de la llamada a la función de reescritura.

Tracé esto a un conjunto de código usando Request.QueryString (en funcionamiento) y el otro usando Request.Url.Query (request.Url devuelve una instancia de Uri).

Aunque he resuelto el error, tengo un problema aquí, así que si cualquiera sabe la diferencia, estoy listo para la lección.

Respuesta

2

Su pregunta realmente despertó mi interés, así que he leído algo durante la última hora o algo así. No estoy absolutamente seguro de haber encontrado la respuesta , pero lo arrojaré t aquí para ver lo que piensas

Según lo que he leído hasta ahora, Request.QueryString es en realidad "una versión analizada de la variable QUERY_STRING en la colección ServerVariables" [reference], donde Request.Url es (como usted indicó) la URL sin formato encapsulada en el Objeto Uri. De acuerdo con this article, el 'constructor' de la clase Uri ... analiza el [url string], lo pone en formato canónico y realiza las codificaciones de escape necesarias. "

Por lo tanto, parece que Request.QueryString utiliza una función diferente para analizar la variable "QUERY_STRING" del constructor ServerVariables. Esto explicaría por qué ves la diferencia entre los dos. Ahora, ¿por qué los diferentes métodos de codificación son utilizados por la función de análisis personalizado y la función de análisis del objeto Uri está completamente más allá de mí. Tal vez alguien más versado en aspnet_isapi DLL podría proporcionar algunas respuestas con esa pregunta.

De todos modos, espero que mi publicación tenga sentido. En una nota lateral, me gustaría agregar otra referencia que también proporcionó una lectura muy completa e interesante: http://download.microsoft.com/download/6/c/a/6ca715c5-2095-4eec-a56f-a5ee904a1387/Ch-12_HTTP_Request_Context.pdf

+0

Ambas propiedades devuelven la misma cadena codificada la mayor parte del tiempo; los constructores y el análisis son irrelevantes en este caso. Solo después de la llamada de reescritura cambia la codificación de Uri. – zombat

+0

Tal vez su respuesta y la respuesta de womps a continuación combinados es la verdad. Quizás es el caso que uno conserva la codificación Url usando un código Latin-1 y el otro usa UTF-8. –

3

Lo que indicó como la cadena codificada "rota" es en realidad la codificación correcta según los estándares. El que indicó como codificación "correcta" está utilizando una extensión no estándar a las especificaciones para permitir un formato de %uXXXX (creo que se supone que indica la codificación UTF-16).

En cualquier caso, la cadena codificada "rota" está bien. Puede usar el siguiente código para probar que:

Uri uri = new Uri("http://www.example.com/test.aspx?search=heřmánek"); 
Console.WriteLine(uri.Query); 
Console.WriteLine(HttpUtility.UrlDecode(uri.Query)); 

Funciona bien. Sin embargo ... en una corazonada, probé urldecode con una página de códigos Latin-1 se especifica, el valor por defecto en lugar de UTF-8:

Console.WriteLine(HttpUtility.UrlDecode(uri.Query, 
      Encoding.GetEncoding("iso-8859-1"))); 

... y me dio la mala valor especificado, 'heÅmánek '.En otras palabras, parece que la llamada a HttpContext.RewritePath() de alguna manera cambia el urlencoding/decodificación para usar la página de códigos Latin-1, en lugar de UTF-8, que es la codificación predeterminada utilizada por los métodos UrlEncode/Decode.

Esto parece un error si me preguntas. Puedes mirar el código RewritePath() en el reflector y ver que definitivamente está jugando con la cadena de consulta, pasándola a todo tipo de funciones de ruta virtual y a algún código IIS no administrado.

Me pregunto si en algún punto del camino, el URI en el núcleo del objeto Request se manipulará con la página de códigos incorrecta. Eso explicaría por qué Request.Querystring (que es simplemente los valores brutos de los encabezados HTTP) sería correcto, mientras que el Uri que utiliza la codificación incorrecta para los diacríticos sería incorrecto.

+0

Me alegra que pienses que es un error. No puedo entender por qué este comportamiento sería así. –

0

He hecho un poco de investigación durante el último día y creo que tengo algo de información sobre esto.

Cuando utiliza Request.Querystring o HttpUtility.UrlDecode (o Encode) está utilizando la codificación que se especifica en el elemento (específicamente el atributo requestEncoding) de la web.config (o la jerarquía .config si no la tiene) t especificado) --- NO la Codificación.Default que es la codificación predeterminada para su servidor.

Cuando tiene la codificación establecida en UTF-8, un único carácter Unicode se puede codificar como valores hexadecimales 2% xx. También se decodificará de esa manera cuando se le dé todo el valor.

Si utiliza UrlDecoding con una codificación diferente de la que se codificó con la url, obtendrá un resultado diferente.

Dado que HttpUtility.UrlEncode y UrlDecode pueden tomar un parámetro de codificación, es tentador intentar codificar usando una página de códigos ANSI, pero UTF-8 es el camino correcto si tiene soporte para el navegador (aparentemente las versiones antiguas no soporte UTF-8). Solo necesita asegurarse de que esté correctamente configurado y que ambos lados funcionen bien.

UTF-8 parece ser la codificación por defecto: (del reflector .net System.Web.HttpRequest)

internal Encoding QueryStringEncoding 
{ 
    get 
    { 
     Encoding contentEncoding = this.ContentEncoding; 
     if (!contentEncoding.Equals(Encoding.Unicode)) 
     { 
      return contentEncoding; 
     } 
     return Encoding.UTF8; 
    } 
} 

Siguiendo el camino para averiguar la this.ContentEncoding que conduce a (también en HttpRequest)

public Encoding ContentEncoding 
{ 
    get 
    { 
     if (!this._flags[0x20] || (this._encoding == null)) 
     { 
      this._encoding = this.GetEncodingFromHeaders(); 
      if (this._encoding == null) 
      { 
       GlobalizationSection globalization = RuntimeConfig.GetLKGConfig(this._context).Globalization; 
       this._encoding = globalization.RequestEncoding; 
      } 
      this._flags.Set(0x20); 
     } 
     return this._encoding; 
    } 
    set 
    { 
     this._encoding = value; 
     this._flags.Set(0x20); 
    } 
} 

Para responder a su pregunta específica sobre la diferencia Transcurrirá Request.Url.Quer y Request.QueryString ... aquí es cómo HttpRequest construye su dirección URL del inmueble:

public Uri Url 
{ 
    get 
    { 
     if ((this._url == null) && (this._wr != null)) 
     { 
      string queryStringText = this.QueryStringText; 
      if (!string.IsNullOrEmpty(queryStringText)) 
      { 
       queryStringText = "?" + HttpEncoder.CollapsePercentUFromStringInternal(queryStringText, this.QueryStringEncoding); 
      } 
      if (AppSettings.UseHostHeaderForRequestUrl) 
      { 
       string knownRequestHeader = this._wr.GetKnownRequestHeader(0x1c); 
       try 
       { 
        if (!string.IsNullOrEmpty(knownRequestHeader)) 
        { 
         this._url = new Uri(this._wr.GetProtocol() + "://" + knownRequestHeader + this.Path + queryStringText); 
        } 
       } 
       catch (UriFormatException) 
       { 
       } 
      } 
      if (this._url == null) 
      { 
       string serverName = this._wr.GetServerName(); 
       if ((serverName.IndexOf(':') >= 0) && (serverName[0] != '[')) 
       { 
        serverName = "[" + serverName + "]"; 
       } 
       this._url = new Uri(this._wr.GetProtocol() + "://" + serverName + ":" + this._wr.GetLocalPortAsString() + this.Path + queryStringText); 
      } 
     } 
     return this._url; 
    } 
} 

Puede ver que está utilizando la clase HttpEncoder para realizar la decodificación, pero utiliza el mismo valor QueryStringEncoding.

Dado que ya estoy publicando una gran cantidad de código aquí y cualquiera puede obtener .NET Reflector, voy a tomar el resto. La propiedad QueryString proviene de HttpValueCollection que utiliza el método FillFromEncodedBytes para eventualmente llamar a HttpUtility.UrlDecode (con el valor QueryStringEncoding establecido anteriormente), que finalmente llama al HttpEncoder para decodificarlo. Parece que usan una metodología diferente para decodificar los bytes reales de la cadena de consulta, pero la codificación que usan para hacerlo parece ser la misma.

Me resulta interesante que HttpEncoder tenga tantas funciones que parecen hacer lo mismo, por lo que es posible que haya diferencias en los métodos que pueden causar un problema.

Cuestiones relacionadas