Qual é a diferença entre EscapeUriString e EscapeDataString?

192

Se apenas lidar com a codificação de URL, devo usar EscapeUriString ?

user496949
fonte
10
Sempre escape cada valor individual usando 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.
Timo

Respostas:

112

Use EscapeDataStringsempre (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

Jcl
fonte
3
Não tenho certeza de que o link realmente forneça mais informações, pois trata-se de um escape sem escape, em vez de escape.
Steven
1
É basicamente a mesma diferença. Se você realmente leu o artigo, há uma tabela no meio que realmente escapa (não escapa) para mostrar as diferenças (comparando URLEncodetambém).
Jcl
2
Ainda não está claro para mim - e se eu não estiver escapando de um URI inteiro, mas apenas parte dele - (ou seja, os dados para um parâmetro de string de consulta)? Estou escapando de dados para o URI ou o EscapeDataString implica algo completamente diferente?
BrainSlugs83
4
... alguns testes parecem que eu quero EscapeDataString para um parâmetro URI. Eu testei com a string "I heart C ++" e o EscapeUriString não codificou os caracteres "+", apenas os deixou como estão, o EscapeDataString os converteu corretamente em "% 2B".
BrainSlugs83
7
Esta é uma resposta ruim. Você nunca deve usar o EscapeUriString, isso não faz nenhum sentido. Veja a resposta de Livven abaixo (e vote-a).
Brandon Paddock
242

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:

  1. Você tem um URI simples, como este:

    http://example.org/

    Uri.EscapeUriString não vai mudar isso.

  2. 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
  3. 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.

  4. Você decide que realmente deseja que o keyparâmetro seja father&son, para corrigir manualmente o URL anterior, escapando do e comercial:

    http://example.org/?parameter=father%26son

    No entanto, Uri.EscapeUriStringtambé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.EscapeUriStringpara 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.EscapeUriStringtambé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.EscapeDataStringpara 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.EscapeUriStringcomo ú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.

Livven
fonte
4
Uau, obrigado por finalmente esclarecer esta questão. As duas respostas anteriores não foram muito úteis.
everpresent
3
Exatamente certo. O EscapeUriString (como o comportamento padrão do EscapeUrl no Win32) foi criado por alguém que não entendeu URIs ou escapou. É uma tentativa equivocada de criar algo que usa um URI malformado e às vezes o transforma na versão pretendida. Mas ele não tem as informações necessárias para fazer isso de maneira confiável. Também costuma ser usado no lugar do EscapeDataString, o que também é muito problemático. Eu gostaria que EscapeUriString não existisse. Todo uso é errado.
Brandon Paddock
4
bem explicada +1 é muito melhor do que ligação aceita única resposta
Ehsan Sajjad
1
Esta resposta precisa de mais atenção. É a maneira correta de fazer isso. As outras respostas têm cenários em que não produzem os resultados pretendidos.
Timo
1
... Claro encodeURI/ Uri.EscapeUriStringnã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.
Crescent Fresh
56

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":

https://www.google.com/?q=happy+cat

Esse é um URI válido (experimente) e EscapeUriStringnão o modificará.

Agora considere consultar o Google para "happy c ++":

https://www.google.com/?q=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 EscapeDataStringe voila * :

https://www.google.com/?q=happy+c%2B%2B

*) 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 UriBuildercomo deveria, precisará EscapeDataStringescapar 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.

Seth
fonte
Obrigado. E quando você tem uma string URI absoluta que precisa codificar, por exemplo "https://www.google.com/?q=happy c++". Parece que eu preciso dividir manualmente "?" Ou existe uma maneira melhor?
wensveen 9/03/2015
Se você estiver passando o URL inteiro como parâmetro para outro URL, use EscapeDataString. Se o URL que você forneceu é o URL real, sim, você deseja apenas dividir ?.
Seth
7

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 . EscapeDataStringescapa deles; EscapeUriStringnã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 EscapeUriStringque seria muito mais útil se ele detectasse esse padrão e evitasse a codificação %quando for imediatamente seguido por 2 dígitos hexadecimais.

Todd Menier
fonte
1

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
*/
Aprendendo
fonte