TL; DR: Verwenden Sie keine akzeptierte Version, da diese in Bezug auf die Behandlung von Unicode-Zeichen völlig fehlerhaft ist, und verwenden Sie niemals die interne API
Ich habe tatsächlich ein seltsames Problem mit der doppelten Codierung bei der akzeptierten Lösung festgestellt:
Wenn Sie also mit Zeichen arbeiten, die codiert werden müssen, führt eine akzeptierte Lösung zu einer doppelten Codierung:
- Abfrageparameter werden mithilfe des
NameValueCollection
Indexers automatisch codiert ( und dies verwendet UrlEncodeUnicode
nicht regelmäßig erwartet UrlEncode
(!) ).
- Wenn Sie dann aufrufen
uriBuilder.Uri
, wird ein neuer Uri
Konstruktor erstellt, der die Codierung noch einmal ausführt (normale URL-Codierung).
uriBuilder.ToString()
Dies kann nicht vermieden werden, indem Sie (obwohl dies korrekt zurückgibt, Uri
welche IMO zumindest inkonsistent ist, möglicherweise ein Fehler, aber das ist eine andere Frage) und dann eine HttpClient
Methode verwenden, die eine Zeichenfolge akzeptiert - der Client erstellt immer noch Uri
aus Ihrer übergebenen Zeichenfolge Folgendes:new Uri(uri, UriKind.RelativeOrAbsolute)
Kleiner, aber voller Repro:
var builder = new UriBuilder
{
Scheme = Uri.UriSchemeHttps,
Port = -1,
Host = "127.0.0.1",
Path = "app"
};
NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
query["cyrillic"] = "кирилиця";
builder.Query = query.ToString();
Console.WriteLine(builder.Query); //query with cyrillic stuff UrlEncodedUnicode, and that's not what you want
var uri = builder.Uri; // creates new Uri using constructor which does encode and messes cyrillic parameter even more
Console.WriteLine(uri);
// this is still wrong:
var stringUri = builder.ToString(); // returns more 'correct' (still `UrlEncodedUnicode`, but at least once, not twice)
new HttpClient().GetStringAsync(stringUri); // this creates Uri object out of 'stringUri' so we still end up sending double encoded cyrillic text to server. Ouch!
Ausgabe:
?cyrillic=%u043a%u0438%u0440%u0438%u043b%u0438%u0446%u044f
https://127.0.0.1/app?cyrillic=%25u043a%25u0438%25u0440%25u0438%25u043b%25u0438%25u0446%25u044f
Wie Sie vielleicht sehen, egal ob Sie uribuilder.ToString()
+ httpClient.GetStringAsync(string)
oder uriBuilder.Uri
+ tunhttpClient.GetStringAsync(Uri)
senden Sie , doppelt codierte Parameter
Ein behobenes Beispiel könnte sein:
var uri = new Uri(builder.ToString(), dontEscape: true);
new HttpClient().GetStringAsync(uri);
Dies verwendet jedoch einen veralteten Uri
Konstruktor
PS in meinem neuesten .NET unter Windows Server, Uri
Konstruktor mit bool doc Kommentar sagt "veraltet, dontEscape ist immer falsch", funktioniert aber tatsächlich wie erwartet (überspringt das Escapezeichen)
Es sieht also nach einem weiteren Fehler aus ...
Und selbst das ist einfach falsch - es sendet UrlEncodedUnicode an den Server, nicht nur UrlEncoded, was der Server erwartet
Update: Eine weitere Sache ist, dass NameValueCollection tatsächlich UrlEncodeUnicode ausführt, das nicht mehr verwendet werden soll und nicht mit regulärem url.encode / decode kompatibel ist (siehe NameValueCollection to URL Query? ).
Das Fazit lautet also: Verwenden Sie diesen Hack niemals,NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
da dies Ihre Unicode-Abfrageparameter durcheinander bringt. Erstellen Sie die Abfrage einfach manuell und weisen Sie sie UriBuilder.Query
der erforderlichen Codierung zu, und verwenden Sie dann UriUriBuilder.Uri
.
Paradebeispiel dafür, wie Sie sich selbst verletzen, indem Sie Code verwenden, der nicht so verwendet werden soll