Quelle est la différence entre EscapeUriString et EscapeDataString?

196

Si seulement traiter l'encodage d'URL, je devrais utiliser EscapeUriString ?

user496949
la source
10
Échappez toujours à chaque valeur individuelle en utilisant Uri.EscapeDataString(), comme expliqué dans la réponse de @ Livven. Avec d'autres approches, le système n'a tout simplement pas assez d'informations pour produire le résultat attendu pour chaque entrée possible.
Timo

Réponses:

112

Utilisez EscapeDataStringtoujours (pour plus d'informations sur les raisons, voir la réponse de Livven ci-dessous)

Edit : suppression du lien mort sur la différence entre les deux sur le codage

Jcl
la source
3
Je ne suis pas sûr que ce lien fournisse plus d'informations car il s'agit de non échapper plutôt que d'esacaping.
Steven
1
C'est fondamentalement la même différence. Si vous lisez réellement l'article, il y a une table autour du milieu qui s'échappe en fait (pas un échappe) pour montrer les différences (en comparaison avec URLEncodeaussi).
Jcl
2
Ce n'est toujours pas clair pour moi - que faire si je n'échappe pas à un URI entier mais seulement à une partie de celui-ci - (c'est-à-dire les données pour un paramètre de chaîne de requête)? Est-ce que j'échappe des données pour l'URI ou est-ce que EscapeDataString implique quelque chose de complètement différent?
BrainSlugs83
4
... fait quelques tests ressemble à Je veux EscapeDataString pour un paramètre URI. J'ai testé avec la chaîne "I heart C ++" et EscapeUriString n'a pas encodé les caractères "+", il les a juste laissés tels quels, EscapeDataString les a correctement convertis en "% 2B".
BrainSlugs83
7
C'est une mauvaise réponse. Vous ne devriez jamais utiliser EscapeUriString, cela n'a aucun sens. Voir la réponse de Livven ci-dessous (et voter pour).
Brandon Paddock
245

Je n'ai pas trouvé les réponses existantes satisfaisantes, j'ai donc décidé de creuser un peu plus pour régler ce problème. Étonnamment, la réponse est très simple:

Il n'y a (presque *) aucune raison valable de l'utiliser Uri.EscapeUriString. Si vous devez encoder en pourcentage une chaîne, utilisez toujours Uri.EscapeDataString.

* Voir le dernier paragraphe pour un cas d'utilisation valide.

Pourquoi est-ce? Selon la documentation :

Utilisez la méthode EscapeUriString pour préparer une chaîne d'URI sans échappement en tant que paramètre du constructeur Uri.

Cela n'a pas vraiment de sens. Selon RFC 2396 :

Un URI est toujours sous une forme «échappée», car échapper ou déséchapper un URI terminé peut changer sa sémantique.

Alors que la RFC citée est devenue obsolète par la RFC 3986 , le point est toujours d'actualité. Vérifions-le en regardant quelques exemples concrets:

  1. Vous avez un URI simple, comme ceci:

    http://example.org/

    Uri.EscapeUriString ne le changera pas.

  2. Vous décidez de modifier manuellement la chaîne de requête sans tenir compte de l'échappement:

    http://example.org/?key=two words

    Uri.EscapeUriString échappera (correctement) à l'espace pour vous:

    http://example.org/?key=two%20words
  3. Vous décidez de modifier encore plus manuellement la chaîne de requête:

    http://example.org/?parameter=father&son

    Cependant, cette chaîne n'est pas modifiée par Uri.EscapeUriString, car elle suppose que l'esperluette signifie le début d'une autre paire clé-valeur. Cela peut ou non être ce que vous vouliez.

  4. Vous décidez que vous voulez en fait que le keyparamètre soit father&son, donc vous corrigez l'URL précédente manuellement en échappant l'esperluette:

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

    Cependant, Uri.EscapeUriStringle caractère de pourcentage échappera également, ce qui entraînera un double encodage:

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

Comme vous pouvez le voir, l'utilisation Uri.EscapeUriStringpour son usage prévu rend impossible l'utilisation& comme partie d'une clé ou d'une valeur dans une chaîne de requête plutôt que comme séparateur entre plusieurs paires clé-valeur.

En effet, pour tenter de le rendre approprié pour échapper des URI complets, il ignore les caractères réservés et n'échappe que les caractères qui ne sont ni réservés ni non réservés, ce qui, BTW, est contraire à la documentation . De cette façon, vous ne vous retrouvez pas avec quelque chose comme http%3A%2F%2Fexample.org%2F, mais vous vous retrouvez avec les problèmes illustrés ci-dessus.


En fin de compte, si votre URI est valide, il n'a pas besoin d'être échappé pour être passé en paramètre au constructeur d'Uri, et s'il n'est pas valide, appelez Uri.EscapeUriString n'est pas non plus une solution magique. En fait, cela fonctionnera dans de nombreux cas sinon dans la plupart des cas, mais ce n'est en aucun cas fiable.

Vous devez toujours créer vos URL et vos chaînes de requête en rassemblant les paires clé-valeur et le codage en pourcentage, puis en les concaténant avec les séparateurs nécessaires. Vous pouvez utiliser Uri.EscapeDataStringà cette fin, mais pas Uri.EscapeUriString, car il n'échappe pas aux caractères réservés, comme mentionné ci-dessus.

Ce n'est que si vous ne pouvez pas faire cela, par exemple lorsque vous traitez avec des URI fournis par l'utilisateur, qu'il est judicieux de l'utiliser Uri.EscapeUriStringen dernier recours. Mais les mises en garde mentionnées précédemment s'appliquent - si l'URI fourni par l'utilisateur est ambigu, les résultats peuvent ne pas être souhaitables.

Livven
la source
4
Wow, merci d'avoir enfin clarifié cette question. Les deux réponses précédentes n'étaient pas très utiles.
EverPresent
3
Exactement raison. EscapeUriString (comme le comportement par défaut d'EscapeUrl dans Win32) a été créé par quelqu'un qui ne comprenait pas les URI ou qui s'échappait. C'est une tentative malavisée de créer quelque chose qui prend un URI mal formé et le transforme parfois en la version voulue. Mais il ne dispose pas des informations nécessaires pour le faire de manière fiable. Il est également fréquemment utilisé à la place d'EscapeDataString, ce qui est également très problématique. Je souhaite que EscapeUriString n'existait pas. Chaque utilisation est erronée.
Brandon Paddock
4
bien expliqué +1 c'est bien mieux que le lien accepté seulement réponse
Ehsan Sajjad
1
Cette réponse nécessite plus d'attention. C'est la bonne façon de procéder. Les autres réponses ont des scénarios où elles ne produisent pas les résultats escomptés.
Timo
1
... Bien sûr encodeURI/ Uri.EscapeUriStringn'est pas nécessaire aussi souvent que encodeURIComponent/ Uri.EscapeDataString(depuis quand faites-vous la sourde oreille avec des URL aveugles qui doivent être utilisées dans un contexte uri), mais cela ne veut pas dire qu'elle n'a pas sa place.
Crescent Fresh
56

Les caractères plus (+) peuvent en dire long sur la différence entre ces méthodes. Dans un URI simple, le caractère plus signifie «espace». Envisagez d'interroger Google sur "chat heureux":

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

C'est un URI valide (essayez-le), et EscapeUriStringne le modifiera pas.

Pensez maintenant à interroger Google pour "happy c ++":

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

C'est un URI valide (essayez-le), mais cela produit une recherche pour "happy c", car les deux plus sont interprétés comme des espaces. Pour le réparer, nous pouvons passer "happy c ++" à EscapeDataStringet voila * :

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

*) La chaîne de données encodée est en fait "happy% 20c% 2B% 2B"; % 20 est hexadécimal pour le caractère espace et% 2B est hexadécimal pour le caractère plus.

Si vous utilisez UriBuildercomme vous le souhaitez, il vous suffira EscapeDataStringd'échapper correctement à certains des composants de l'ensemble de votre URI. La réponse de @ Livven à cette question prouve en outre qu'il n'y a vraiment aucune raison d'utiliser EscapeUriString.

Seth
la source
Merci. Qu'en est-il lorsque vous avez une chaîne URI absolue que vous devez encoder, par exemple "https://www.google.com/?q=happy c++". Il semble que j'ai besoin de fractionner manuellement sur "?", Ou y a-t-il un meilleur moyen?
wensveen
Si vous transmettez l'URL entière en tant que paramètre à une autre URL, utilisez EscapeDataString. Si l'URL que vous avez fournie est l'URL réelle, alors oui, vous voulez simplement diviser ?.
Seth
7

Commentaires dans la source abordent clairement la différence. Pourquoi ces informations ne sont pas transmises via les commentaires de documentation XML est un mystère pour moi.

EscapeUriString:

Cette méthode échappera à tout caractère qui n'est pas un caractère réservé ou non réservé, y compris les signes de pourcentage. Notez que EscapeUriString n'échappera pas non plus au signe «#».

EscapeDataString:

Cette méthode échappera à tout caractère qui n'est pas un caractère non réservé, y compris les signes de pourcentage.

La différence réside donc dans la manière dont ils gèrent les caractères réservés . EscapeDataStringleur échappe;EscapeUriStringne fait pas.

Selon la RFC , les caractères réservés sont::/?#[]@!$&'()*+,;=

Par souci d'exhaustivité, les caractères non réservés sont alphanumériques et -._~

Les deux méthodes échappent aux caractères qui ne sont ni réservés ni non réservés.

Je suis en désaccord avec le général notion qui EscapeUriStringest mal. Je pense qu'une méthode qui échappe uniquement aux caractères illégaux (tels que les espaces) et non aux caractères réservés est utile. Mais il a une bizarrerie dans la façon dont il gère le %personnage. Les caractères codés en pourcentage ( %suivis de 2 chiffres hexadécimaux) sont autorisés dans un URI. Je pense que ce EscapeUriStringserait beaucoup plus utile s'il détectait ce modèle et évitait le codage %lorsqu'il était immédiatement procédé par 2 chiffres hexadécimaux.

Todd Menier
la source
1

Un exemple simple

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
*/
Apprentissage
la source