The hash-bang theory

Ce billet date de plusieurs années, ses informations peuvent être devenues obsolètes.

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

#1 benoit

05/06/2011 18:07

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.

#2 kemar

05/06/2011 18:09

@benoit haha c'est pas faux ! Je corrige ça :)

#3 Mathieu

06/06/2011 10:25

Personnellement je suis adepte de l'approche inverse.

Un site doit proposer nativement des urls parfaitement standard le FragmentToken fait donc partie de mon URL

dans la source des pages on trouvera donc http://monsite.com/FragmentToken/a/b/c

Ce sont des liens parfaitement valide et qui mène vers des pages de la manière la plus naturelle qui soit

Ensuite le javascript passe par dessus et remplace les liens pour obtenir des choses du genre http://monsite.com#a/b/c

Du coup sans javascript le site reste parfaitement consultable et son référencement naturel ne pose pas de problème.

Avant Assouplissons-nous quantitativement Après L'échec des propriétés CSS expérimentales

Tag Kemar Joint