TL; DR: n'utilisez pas la version acceptée car elle est complètement cassée par rapport à la gestion des caractères unicode, et n'utilisez jamais d'API interne
J'ai en fait trouvé un problème de double encodage étrange avec la solution acceptée:
Donc, si vous avez affaire à des caractères qui doivent être encodés, la solution acceptée conduit à un double encodage:
- les paramètres de requête sont automatiquement codés à l'aide de l'
NameValueCollection
indexeur ( et cela utilise UrlEncodeUnicode
, pas normalement prévu UrlEncode
(!) )
- Ensuite, lorsque vous appelez,
uriBuilder.Uri
il crée un nouveau Uri
constructeur utilisant qui encode une fois de plus (encodage url normal)
- Cela ne peut pas être évité en faisant
uriBuilder.ToString()
(même si cela renvoie correct Uri
quel IMO est au moins incohérent, peut-être un bogue, mais c'est une autre question), puis en utilisant la HttpClient
méthode acceptant la chaîne - le client crée toujours à Uri
partir de votre chaîne passée comme ceci:new Uri(uri, UriKind.RelativeOrAbsolute)
Petit, mais repro complet:
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!
Production:
?cyrillic=%u043a%u0438%u0440%u0438%u043b%u0438%u0446%u044f
https://127.0.0.1/app?cyrillic=%25u043a%25u0438%25u0440%25u0438%25u043b%25u0438%25u0446%25u044f
Comme vous pouvez le voir, peu importe si vous faites uribuilder.ToString()
+ httpClient.GetStringAsync(string)
ou uriBuilder.Uri
+ httpClient.GetStringAsync(Uri)
vous finissez par envoyer un paramètre codé en double
Un exemple fixe pourrait être:
var uri = new Uri(builder.ToString(), dontEscape: true);
new HttpClient().GetStringAsync(uri);
Mais cela utilise un Uri
constructeur obsolète
PS sur mon dernier .NET sur Windows Server, le Uri
constructeur avec un commentaire booléen dit "obsolète, dontEscape est toujours faux", mais fonctionne en fait comme prévu (saute l'échappement)
Donc ça ressemble à un autre bug ...
Et même cela est tout simplement faux - il envoie UrlEncodedUnicode au serveur, pas seulement UrlEncoded ce que le serveur attend
Mise à jour: une dernière chose est que NameValueCollection fait réellement UrlEncodeUnicode, qui n'est plus censé être utilisé et est incompatible avec url.encode / décodage régulier (voir NameValueCollection to URL Query? ).
Donc, l'essentiel est: n'utilisez jamais ce hack avecNameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
car cela perturberait vos paramètres de requête Unicode. Créez simplement la requête manuellement et assignez-la à UriBuilder.Query
laquelle effectuera le codage nécessaire, puis obtenez Uri à l'aide de UriBuilder.Uri
.
Premier exemple de vous blesser en utilisant du code qui n'est pas censé être utilisé comme ça