2010-02-08 1 views
12

Ich habe einen Fehler in einer Url Rewriting-Anwendung gefunden. Der Fehler wurde bei einigen diakritischen Zeichen in der Querystring als Codierungsproblem angezeigt.Was ist der Unterschied zwischen Request.Url.Query und Request.QueryString?

Im Grunde war das Problem, dass eine Anforderung, die im Grunde war /search.aspx?search=heřmánek wurde mit einem Abfragezeichenfolgeflag von "search = er% c5% 99m% c3% a1nek" neu geschrieben zu werden

Der richtige Wert (mit einem anderen, funktionierenden Code) war eine Neuschreibung der Querystring als "Suche = er% u0159m% u00e1nek"

Beachten Sie den Unterschied zwischen den beiden Zeichenfolgen. Wenn Sie jedoch beides veröffentlichen, sehen Sie, dass die URL-Codierung dieselbe Zeichenfolge reproduziert. Es ist nicht, bis Sie die context.Rewrite-Funktion verwenden, die die Codierung unterbricht. Die unterbrochene Zeichenkette gibt 'heÅmánek' zurück (mit Request.QueryString ["Search"]) und die funktionierende Zeichenkette gibt 'heřmánek' zurück. Diese Änderung geschieht nach dem Aufruf der Umschreibfunktion.

Ich führte dies auf eine Menge zurück der Code mit Request.QueryString (in Arbeit) und der andere mit Request.Url.Query (request.Url gibt eine Uri-Instanz zurück.)

Während ich den Fehler herausgearbeitet habe, gibt es hier ein Loch in meinem Verständnis, also wenn Jeder weiß den Unterschied, ich bin bereit für den Unterricht.

Antwort

2

Ihre Frage hat wirklich mein Interesse geweckt, also habe ich in der letzten Stunde etwas gelesen .. Ich bin nicht absolut sicher, dass ich die Antwort gefunden habe , aber ich werde es rauswerfen hier um zu sehen was du denkst.

Von was ich bis jetzt gelesen habe, ist Request.QueryString tatsächlich "eine geparste Version der QUERY_STRING-Variable in der ServerVariables-Auflistung" [reference], wo wie Request.Url die rohe URL ist, die in der Uri-Objekt. Laut this article analysiert der Konstruktor der Uri-Klasse "... den [url string], setzt ihn in das kanonische Format und führt alle erforderlichen Escape-Kodierungen aus."

Daher scheint Request.QueryString eine andere Funktion zum Parsen der Variablen "QUERY_STRING" aus dem ServerVariables-Konstruktor verwendet. Dies würde erklären, warum Sie den Unterschied zwischen den beiden sehen. Nun, warum verschiedene Codierungsmethoden von der benutzerdefinierten Parsing-Funktion verwendet werden und die Parsing-Funktion des Uri-Objekts ist völlig außer mir. Vielleicht jemand, der ein bisschen mehr versiert auf der aspnet_isapi DLL könnte einige Antworten mit dieser Frage bieten.

Wie auch immer, hoffentlich macht meine Post Sinn. Nebenbei möchte ich eine weitere Referenz hinzufügen, die auch für eine sehr gründliche und interessante Lektüre sorgte: http://download.microsoft.com/download/6/c/a/6ca715c5-2095-4eec-a56f-a5ee904a1387/Ch-12_HTTP_Request_Context.pdf

+0

Beide Eigenschaften geben die gleiche codierte Zeichenfolge die meiste Zeit zurück - die Konstruktoren und die Analyse sind in diesem Fall irrelevant. Erst nach dem Rewrite-Aufruf ändert sich die Codierung des Uri. – zombat

+0

Vielleicht ist Ihre Antwort und Womps unten kombiniert die Wahrheit. Vielleicht bewahrt man die Url-Codierung mit einem Latin-1-Code, während die andere UTF-8 verwendet. –

3

Was Sie als "gebrochene" kodierte Zeichenfolge angegeben haben, ist eigentlich die korrekte Kodierung nach Standards. Die eine, die Sie als "korrekte" Kodierung angegeben haben, verwendet eine nicht-standardmäßige Erweiterung zu den Spezifikationen, um ein Format von %uXXXX zu ermöglichen (ich glaube, dass es UTF-16 Kodierung anzeigen soll).

In jedem Fall ist die "gebrochene" codierte Zeichenfolge in Ordnung. Sie können den folgenden Code verwenden, um das zu testen:

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

Funktioniert gut. Allerdings ... auf eine Ahnung, ich versuchte urldecode mit einem Latin-1-Codepage angegeben, anstelle des Standard-UTF-8:

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

... und ich bekam den schlechten Wert, den Sie festgelegt, ‚heÅmánek ".Mit anderen Worten, es sieht so aus, als ob der Aufruf an HttpContext.RewritePath() die Urlencodierung/Decodierung irgendwie ändert, um die Latin-1-Codepage anstelle von UTF-8 zu verwenden, die die Standardcodierung ist, die von den UrlEncode/Decode-Methoden verwandt wird.

Das sieht wie ein Fehler aus, wenn Sie mich fragen. Sie können sich den RewritePath() Code in reflector ansehen und sehen, dass er definitiv mit dem Querystring spielt - indem er ihn an alle Arten von virtuellen Pfadfunktionen und an einige nicht verwalteten IIS-Code weitergibt.

Ich frage mich, ob irgendwo auf dem Weg, der Uri im Kern des Request-Objekts mit der falschen Codepage manipuliert wird? Das würde erklären, warum Request.Querystring (was einfach die Rohwerte aus den HTTP-Headern ist) korrekt wäre, während der URI, der die falsche Codierung für die diakritischen Zeichen verwendet, falsch wäre.

+0

Ich bin froh, dass Sie denken, dass es ein Fehler ist. Ich kann nicht herausfinden, warum dieses Verhalten so wäre. –

0

Ich habe ein wenig Forschung über den letzten Tag oder so getan, und ich denke, dass ich einige Informationen dazu habe.

Wenn Sie Request.Querystring oder HttpUtility.UrlDecode (oder Encode) verwenden, verwendet es die Codierung, die in dem Element (speziell dem Attribut requestEncoding) der Datei web.config (oder der .config-Hierarchie angegeben ist). t angegeben) --- NICHT die Encoding.Default, die die Standard-Codierung für Ihren Server ist.

Wenn die Codierung auf UTF-8 eingestellt ist, kann ein einzelnes Unicode-Zeichen als 2% xx-Hexadezimalwerte codiert werden. Es wird auch so dekodiert, wenn der gesamte Wert angegeben wird.

Wenn Sie UrlDecoding mit einer anderen Codierung verwenden als die URL, mit der codiert wurde, erhalten Sie ein anderes Ergebnis.

Da HttpUtility.UrlEncode und UrlDecode einen Codierungsparameter annehmen können, ist es verlockend zu versuchen, mit einer ANSI-Codepage zu kodieren, aber UTF-8 ist der richtige Weg, wenn Sie die Browserunterstützung haben (anscheinend alte Versionen nicht) Unterstützung UTF-8). Sie müssen nur sicherstellen, dass das richtig eingestellt ist und beide Seiten gut funktionieren.

UTF-8 scheint die Standard-Kodierung zu sein: (von .net Reflektor System.Web.HttpRequest)

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

dem Weg Nach dem this.ContentEncoding, um herauszufinden, führt zu (auch in 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); 
    } 
} 

Um Ihre Frage auf der Differenz betwen Request.Url.Quer und Request.QueryString zu beantworten ... hier ist, wie Httprequest seiner Eigenschaft URL baut:

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; 
    } 
} 

Sie können sehen, dass es die HttpEncoder-Klasse verwendet, um die Decodierung durchzuführen, aber es verwendet denselben QueryStringEncoding-Wert.

Da ich bereits eine Menge Code hier schreibe und jeder .NET Reflektor bekommen kann, werde ich den Rest entschlüsseln. Die QueryString-Eigenschaft stammt von der HttpValueCollection, die die FillFromEncodedBytes-Methode verwendet, um HttpUtility.UrlDecode (mit dem oben angegebenen QueryStringEncoding-Wert) aufzurufen, der schließlich den HttpEncoder aufruft, um es zu decodieren. Sie scheinen unterschiedliche Methoden zu verwenden, um die tatsächlichen Bytes der Querystring zu dekodieren, aber die Codierung, die sie verwenden, scheint die gleiche zu sein.

Es ist interessant für mich, dass der HttpEncoder hat so viele Funktionen, die das gleiche zu tun scheinen, so ist es möglich, gibt es Unterschiede in diesen Methoden, die ein Problem verursachen können.

Verwandte Themen