L'utilisation grandissante d'XHR et la transition lente mais sûre vers HTML5 poussent incontestablement le web vers une logique applicative.
Une multitude de nouveaux sites web sont donc constitués sur la base d'une interface à page unique (notamment les applications web mobile) et par conséquent d'une URI unique dans laquelle des portions de données sont mises à jour.
Pour pallier le problème de l'URI unique et parvenir à fournir une URI différente pour chaque état de l'application, on a utilisé l'identifiant de fragment comme solution de contournement.
Or ceci n'est pas sans poser quelques problèmes d'une part vu l'aspect fondamental des URI dans l'architecture du web, et d'autre part en termes de SEO. C'est d'ailleurs la raison pour laquelle Google a proposé la solution du hash-bang.
Son emploi à gogo dans les URIs a récemment donné matière à réflexion et les avis sur la question divergent.
Petit tour d'horizon en attendant des jours meilleurs.
Évolution du signe dièse (#) dans les URIs
Au commencement était l'identification indirecte d'une ressource secondaire.
Tim Berners-Lee expliquait en 1997 dans ses notes personnelles le rôle du signe dièse pour discerner l'identifiant de fragment. Il est d'ailleurs intéressant de noter qu'il ne limite pas son rôle à la seule identification d'une portion de document :
It also means that for any new data type one can be creative about using the fragment ID in a relevant way. For example, for a 3D object the fragment ID could give a viewport. For a music object, the Fragment ID could give a section in time, or a set of parts, or it could include a suggested tempo.
La dernière RFC en date à propos de la syntaxe des URIs consacre une section dédiée aux identifiants de fragment et vous pouvez aussi trouver une définition dans la traduction française d'Architecture du World Wide Web.
Puis vint le temps de l'Ajax et le fameux hack du fragment identifier.
Le dièse dans l'URI est maintenant aussi utilisé pour capturer l'état d'une application web. Les hash-bang URIs font partie de cette catégorie avec l'avantage d'être indexables par Google via un mécanisme de mapping permettant aux Googlebots (uniquement) de parser les URIs hash-bangées. Ce mécanisme est obligatoire puisque les serveurs HTTP ne reçoivent jamais les identifiants de fragment du client :
Because HTTP servers generally deal only with entire objects, not with fragments of objects, clients don't pass fragments along to servers (see Figure 2-3). After your browser gets the entire resource from the server, it then uses the fragment to display the part of the resource in which you are interested.
Mais quid de la pérennité technique de cette solution ? Et les autres web crawlers vont-ils l'implémenter aussi ?
Il est intéressant de noter que le W3C réfléchit sur l'évolution du rôle du signe dièse dans les URIs et tente de mettre à plat de nouvelles best practices.
Pourquoi utiliser les hash-bang URIs ?
L'identifiant de fragment est pour le moment la seule partie d'une URI qui est modifiable sans avoir à rafraîchir toute la page. C'est la raison pour laquelle il est utilisé dans le but de conserver l'état d'une application web ajax via un marque-page dans les cas où c'est le contenu principal qui est modifié via XHR. Bienvenue à la fête du window.onhashchange pour MooTools ou jQuery par exemple.
Voici les raisons d'utiliser les hash-bang URIs qui me paraissent plus ou moins valables :
- protéger l'état côté client pendant l'exécution d'un processus lourd (lecture d'une vidéo...)
- améliorer les performances et conserver une interface réactive en récupérant seulement des fragments de contenu
- rester indexable par Google
Mais les hash-bang URIs déplacent les dispatchers du serveur vers le client et cassent le contrat d'une ressource identifiée par une URI : curl 'http://twitter.com/#!/_kemar/status/76966956409962496'
ne retourne pas le tweet original.
JavaScript obligatoire
Le gros désavantage de l'utilisation de la technique du hash est de reposer entièrement sur JavaScript.
Parfois j'ai l'impression que toutes ces années passées à essayer de mettre en place des techniques de dégradation élégante et d'amélioration progressive sont tombées aux oubliettes.
Et comme souligné dans le post Going Postel dont le titre est à lui seul un concentré de culture web :
Remove JavaScript and some behavioural enhancements will no longer function, but everything will still be addressable and accessible. Remove CSS and your lovely visual design will evaporate, but your content will still be addressable and accessible. There aren’t many other platforms that can offer such a robust level of loose coupling.
Pourtant cela fait quelques années maintenant que l'on est en train de re-déplacer l'intelligence côté client. Essayez de faire fonctionner une application Google, Twitter ou même une application web mobile sans JavaScript, ça n'est pas possible.
En ce qui me concerne je trouve tout cela particulièrement symptomatique de la transition d'un web orienté document vers un web orienté application.
Toute la question qui se pose est de savoir comment effectuer cette transition sans casser les URIs : Impenetrable Hedge of Complexity (via).
Solutionner le problème
La réponse en préparation du côté du groupe de travail actuel est l'HTML5 History API. Mais comme d'habitude ça n'est pas pour tout de suite encore que Github, Facebook et Flickr ont déjà sauté le pas.
L'objet history
se voit doté de deux nouvelles méthodes (pushState
et replaceState
) et d'un nouvel événement (onpopstate
) qui permettent de changer l'URI actuelle sans effectuer de nouvelle requête HTTP tout en conservant les boutons de navigation fonctionnels. Le gros avantage est d'utiliser de véritables URIs qui pointeront tout de même vers quelque chose si le client HTTP ne dispose pas de JavaScript et si le développeur a bien fait son travail. Tout cela est détaillé dans Degradable JavaScript Applications Using HTML5 pushState.
Je me demande encore si le risque de dupliquer les routes entre le client et le serveur n'est pas trop élevé mais on vérifiera ça dans la pratique :)
Il te faut surtout escaper le caractère # qui est pris en compte / évalué par bash.
$> curl 'http://twitter.com/\#\!/_kemar/status/76966956409962496'
te sera plus efficace.