Respostas:
Use EscapeDataString
sempre (para obter mais informações sobre o motivo, consulte a resposta de Livven abaixo)
Editar : link morto removido para saber como os dois diferem na codificação
URLEncode
também).
Como as respostas existentes não foram satisfatórias, resolvi me aprofundar um pouco mais para resolver esse problema. Surpreendentemente, a resposta é muito simples:
Não há (quase *) motivo válido para usar Uri.EscapeUriString
. Se você precisar codificar por cento uma string, sempre use Uri.EscapeDataString
.
* Consulte o último parágrafo para obter um caso de uso válido.
Por que é isso? De acordo com a documentação :
Use o método EscapeUriString para preparar uma seqüência de caracteres URI sem escape para ser um parâmetro para o construtor Uri.
Isso realmente não faz sentido. De acordo com a RFC 2396 :
Um URI está sempre em um formato "escapado", pois escapar ou remover um URI completo pode alterar sua semântica.
Embora a RFC citada tenha sido obsoleta pela RFC 3986 , o ponto ainda permanece. Vamos verificar olhando alguns exemplos concretos:
Você tem um URI simples, como este:
http://example.org/
Uri.EscapeUriString
não vai mudar isso.
Você decide editar manualmente a cadeia de consulta sem considerar escapar:
http://example.org/?key=two words
Uri.EscapeUriString
(corretamente) escapará do espaço para você:
http://example.org/?key=two%20words
Você decide editar manualmente a sequência de consultas ainda mais:
http://example.org/?parameter=father&son
No entanto, essa cadeia de caracteres não é alterada Uri.EscapeUriString
, pois assume que o "e comercial" significa o início de outro par de valores-chave. Isso pode ou não ser o que você pretendia.
Você decide que realmente deseja que o key
parâmetro seja father&son
, para corrigir manualmente o URL anterior, escapando do e comercial:
http://example.org/?parameter=father%26son
No entanto, Uri.EscapeUriString
também escapará o caractere de porcentagem, levando a uma codificação dupla:
http://example.org/?parameter=father%2526son
Como você pode ver, o uso Uri.EscapeUriString
para o objetivo a que se destina torna impossível o uso &
como parte de uma chave ou valor em uma sequência de consultas, e não como um separador entre vários pares de valores-chave.
Isso ocorre porque, na tentativa de torná-lo adequado para escapar de URIs completos, ele ignora caracteres reservados e apenas escapa caracteres que não são reservados nem reservados, o que, BTW, é contrário à documentação . Dessa forma, você não acaba com algo assim http%3A%2F%2Fexample.org%2F
, mas acaba com os problemas ilustrados acima.
No final, se seu URI é válido, ele não precisa ser escapado para ser passado como um parâmetro para o construtor Uri e, se não for válido, chamar Uri.EscapeUriString
também não é uma solução mágica. Na verdade, ele funcionará em muitos, se não na maioria dos casos, mas não é de forma alguma confiável.
Você sempre deve construir seus URLs e cadeias de consulta reunindo os pares de valores-chave e codificação de porcentagem e concatenando-os com os separadores necessários. Você pode usar Uri.EscapeDataString
para esse fim, mas não Uri.EscapeUriString
, pois não escapa caracteres reservados, como mencionado acima.
Somente se você não puder fazer isso, por exemplo, ao lidar com URIs fornecidos pelo usuário, faz sentido usar Uri.EscapeUriString
como último recurso. Mas as advertências mencionadas anteriormente se aplicam - se o URI fornecido pelo usuário for ambíguo, os resultados podem não ser desejáveis.
encodeURI
/ Uri.EscapeUriString
não é necessário com tanta frequência quanto encodeURIComponent
/ Uri.EscapeDataString
(desde quando você está lidando com URLs cegos que devem ser usados em um contexto de URL), mas isso não significa que ele não tem seu lugar.
Os caracteres de mais (+) podem revelar muito sobre a diferença entre esses métodos. Em um URI simples, o caractere mais significa "espaço". Considere consultar o Google para "gato feliz":
Esse é um URI válido (experimente) e EscapeUriString
não o modificará.
Agora considere consultar o Google para "happy c ++":
Esse é um URI válido (tente), mas produz uma pesquisa por "happy c", porque as duas vantagens são interpretadas como espaços. Para corrigi-lo, podemos passar "happy c ++" para EscapeDataString
e voila * :
*) A cadeia de dados codificada é realmente "feliz% 20c% 2B% 2B"; % 20 é hexadecimal para o caractere de espaço e% 2B é hexadecimal para o caractere de mais.
Se você estiver usando UriBuilder
como deveria, precisará EscapeDataString
escapar apenas de alguns dos componentes de todo o seu URI. A resposta de @ Livven a esta pergunta prova ainda que não há realmente motivo para usá-lo EscapeUriString
.
"https://www.google.com/?q=happy c++"
. Parece que eu preciso dividir manualmente "?" Ou existe uma maneira melhor?
EscapeDataString
. Se o URL que você forneceu é o URL real, sim, você deseja apenas dividir ?
.
Os comentários na fonte abordam a diferença claramente. Por que essas informações não são apresentadas por meio de comentários na documentação XML, é um mistério para mim.
EscapeUriString:
Esse método escapará a qualquer caractere que não seja reservado ou não reservado, incluindo sinais de porcentagem. Observe que EscapeUriString também não escapa de um sinal '#'.
EscapeDataString:
Este método escapará a qualquer caractere que não seja um caracter não reservado, incluindo sinais de porcentagem.
Portanto, a diferença está em como eles lidam com caracteres reservados . EscapeDataString
escapa deles; EscapeUriString
não.
De acordo com a RFC , os caracteres reservados são::/?#[]@!$&'()*+,;=
Para completar, os caracteres não reservados são alfanuméricos e -._~
Ambos os métodos escapam de caracteres que não são reservados nem reservados.
Não concordo com a noção geral de que EscapeUriString
é mau. Eu acho que um método que escapa apenas caracteres ilegais (como espaços) e caracteres não reservados é útil. Mas ele tem uma peculiaridade em como ele lida com o %
personagem. Os caracteres codificados em porcentagem ( %
seguidos por 2 dígitos hexadecimais) são válidos em um URI. Eu acho EscapeUriString
que seria muito mais útil se ele detectasse esse padrão e evitasse a codificação %
quando for imediatamente seguido por 2 dígitos hexadecimais.
Um exemplo simples
var data = "example.com/abc?DEF=あいう\x20えお";
Console.WriteLine(Uri.EscapeUriString(data));
Console.WriteLine(Uri.EscapeDataString(data));
Console.WriteLine(System.Net.WebUtility.UrlEncode(data));
Console.WriteLine(System.Web.HttpUtility.UrlEncode(data));
/*
=>
example.com/abc?DEF=%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86+%E3%81%88%E3%81%8A
example.com%2fabc%3fDEF%3d%e3%81%82%e3%81%84%e3%81%86+%e3%81%88%e3%81%8a
*/
Uri.EscapeDataString()
, conforme explicado na resposta de @ Livven. Com outras abordagens, o sistema simplesmente não possui informações suficientes para produzir o resultado pretendido para cada entrada possível.