TL; DR: no use la versión aceptada ya que está completamente rota en relación con el manejo de caracteres Unicode, y nunca use API interna
De hecho, he encontrado un extraño problema de doble codificación con la solución aceptada:
Entonces, si se trata de caracteres que necesitan ser codificados, la solución aceptada conduce a una doble codificación:
- los parámetros de consulta se codifican automáticamente mediante el uso de
NameValueCollectionindexador ( y esto utiliza UrlEncodeUnicode, no se espera regularmente UrlEncode(!) )
- Luego, cuando lo llama
uriBuilder.Uri, crea un nuevo Uriconstructor usando que codifica una vez más (codificación de URL normal)
- Eso no se puede evitar haciendo
uriBuilder.ToString() (a pesar de que esto devuelve correcto Uriqué IMO es al menos inconsistencia, tal vez un error, pero esa es otra pregunta) y luego usando el HttpClientmétodo de aceptación de cadena: el cliente aún crea a Uripartir de su cadena pasada de esta manera:new Uri(uri, UriKind.RelativeOrAbsolute)
Pequeño pero completo 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!
Salida:
?cyrillic=%u043a%u0438%u0440%u0438%u043b%u0438%u0446%u044f
https://127.0.0.1/app?cyrillic=%25u043a%25u0438%25u0440%25u0438%25u043b%25u0438%25u0446%25u044f
Como puede ver, no importa si hace uribuilder.ToString()+ httpClient.GetStringAsync(string)o uriBuilder.Uri+ httpClient.GetStringAsync(Uri), termina enviando un parámetro codificado doble
Ejemplo fijo podría ser:
var uri = new Uri(builder.ToString(), dontEscape: true);
new HttpClient().GetStringAsync(uri);
Pero esto usa un constructor obsoleto Uri
PS en mi último .NET en Windows Server, el Uriconstructor con el comentario de bool doc dice "obsoleto, dontEscape siempre es falso", pero en realidad funciona como se espera (se escapa)
Entonces parece otro error ...
E incluso esto es simplemente incorrecto: envía UrlEncodedUnicode al servidor, no solo UrlEncoded lo que el servidor espera
Actualización: una cosa más es que NameValueCollection realmente hace UrlEncodeUnicode, que se supone que ya no se debe usar y es incompatible con url.encode / decode (¿Ver NameValueCollection to URL Query? ).
Entonces, la conclusión es: nunca use este truco,NameValueCollection query = HttpUtility.ParseQueryString(builder.Query); ya que alterará sus parámetros de consulta Unicode. Simplemente construya la consulta manualmente y asígnele lo UriBuilder.Queryque hará la codificación necesaria y luego use Uri UriBuilder.Uri.
Primer ejemplo de lastimarse a sí mismo usando un código que no se debe usar de esta manera