Dans un projet récent, nous avons été chargés de créer la version mobile d'un site web existant. Le site web existant n'était pas vraiment un bon candidat pour un design réactif, nous avons donc décidé de créer une version complètement nouvelle du site pour les appareils mobiles.

_(photo par Johan Larsson)
Au départ, nous pensions utiliser le modèle m.example.com, où les sites sont des domaines entièrement séparés. Cependant, puisque nous ne gérons pas l'infrastructure pour ce site, nous voulions opter pour une approche nécessitant le moins de changements d'infrastructure possible. Prendre en charge un autre domaine sur les mêmes serveurs n'est pas très difficile, mais c'est une autre tâche qui est facile à manquer et qui n'est pas nécessaire dans notre cas.
J'ai également publié cette technique pour que tout le monde puisse l'utiliser facilement dans une application rails via un moteur rails :
- https://github.com/milesmatthias/cdddn
- http://rubygems.org/gems/cdddn
Introduction à CloudFront
Un énorme avantage de ce site web particulier est qu'il utilise CloudFront. CloudFront est un réseau de distribution de contenu (ou CDN), où les pages web statiques sont hébergées dans 52 centres de données à travers le monde. Cela permet à la page d'être servie au navigateur le plus rapidement possible, car peu importe où vous vous trouvez dans le monde, vous ne serez pas loin de l'un des nœuds de CloudFront, ce qui prendra moins de temps pour que le site web soit délivré à votre appareil. CloudFront fait partie de l'offre AWS d'Amazon et, en plus de garantir la vitesse, ils garantissent la disponibilité. (Contrairement à S3, où seule la disponibilité est garantie.)
Lorsque vous utilisez CloudFront, vous lui indiquez où se trouve votre serveur web afin que CloudFront puisse obtenir la dernière version des pages web qu'il sert pour vous. CloudFront demande également à votre serveur web de nouvelles versions de vos pages web tous les quelques minutes, ou à l'intervalle de temps que vous configurez dans votre tableau de bord CloudFront. Normalement, c'est quelque part autour de 24 heures. Cela permet à CloudFront de se concentrer sur la disponibilité et la vitesse, tout en réduisant considérablement la charge sur votre serveur web. (Il faut également du temps à CloudFront pour prendre une nouvelle version d'une page et mettre à jour les 52 centres de données.)
Cependant, cela introduit le problème du suivi de l'état. Par exemple, si votre site est entièrement servi par CloudFront, comment gérez-vous la connexion des utilisateurs à votre site ? Si je suis un utilisateur nommé Bob et que la page à /my/account
dit "Bonjour Bob !", CloudFront pensera que tout le monde qui demande la page à /my/account
devrait voir la version de la page qui dit "Bonjour Bob !". Les utilisateurs (sauf peut-être ceux qui s'appellent Bob...) seront très confus. Non seulement cela, mais que se passe-t-il si un utilisateur met à jour une valeur dans son compte et s'attend à ce que ce changement s'affiche instantanément ? CloudFront n'obtient pas une nouvelle version de la page à chaque demande (ce qui déferait en quelque sorte le but de CloudFront), il attend quelques minutes pour obtenir une nouvelle version. CloudFront a répondu à plusieurs de ces questions avec de nouvelles fonctionnalités, mais vous devez être conscient de ces implications lors de l'utilisation de CloudFront.
Dans notre cas, le site sur lequel nous travaillons n'a pas le concept d'"utilisateurs" et personne ne peut se connecter au système. Cependant, nous voulons toujours que CloudFront montre différentes versions du site en fonction de l'appareil à partir duquel vous demandez le site (mobile vs bureau).
CloudFront peut effectuer une détection de l'appareil pour vous et envoyer ensuite un en-tête spécial à votre serveur web pour dire "Donnez-moi la version de la page pour un téléphone", cependant, nous voulions contrôler la méthode de détection de l'appareil (en répondant à la question - est-ce un téléphone ou un bureau ?) et nous voulions la possibilité pour les utilisateurs finaux et les développeurs de remplacer l'appareil choisi pour eux. Par exemple, les utilisateurs finaux sur une tablette peuvent simplement vouloir voir la version bureau même si nous leur montrons initialement la version mobile. Nos développeurs trouveront également cela ennuyeux de changer leur appareil chaque fois qu'ils veulent passer entre les versions lors de la construction du site.
Notre Solution
Voici donc la méthode que nous avons trouvée pour avoir à la fois une version bureau et mobile d'un site sur le même domaine et servie par CloudFront. Une note requise est que CloudFront désactive normalement tous les cookies pour votre domaine, mais vous pouvez le configurer pour autoriser les cookies que vous nommez. Dans notre cas, nous avons dit à CloudFront d'autoriser un cookie appelé 'device'. Notez également que nous sommes dans le contexte d'une application rails 4, mais cette architecture peut être reproduite dans n'importe quelle pile. Le point principal ici est que le client doit déterminer quel appareil l'utilisateur utilise, lui permettre de le remplacer et garder le serveur informé du type d'appareil afin que le serveur puisse servir les bonnes pages (cela est fait via des cookies).
Sur chaque page, nous devons faire quelque chose comme ceci (extrait de app/views/layout/application.html.erb)
<%= javascript_include_tag "mobile_detection" %>
<script>
if (!window.location.href.match(/get_device|set_device/)){
console.log('logging the window.location.href = ' + window.location.href);
localStorage.setItem('referrer_href', window.location.href);
}
var device_cookie = cookie.get('device'),
cookiesEnabled = cookie.enabled();
if (cookiesEnabled && device_cookie == undefined) {
window.location = '/get_device.html'
}
</script>
Le code ci-dessus se souvient simplement de la page sur laquelle vous avez atterri (généralement la page d'accueil, mais nous voulons que le client puisse partager des liens et que cela fonctionne également sur mobile), puis vous redirige vers la page /get_device
pour détecter votre appareil si nous n'avons pas encore fait cela. Notez l'utilisation de localStorage
, ce qui signifie que cela ne fonctionnera que sur IE8+ et ne fonctionnera pas sur Opera Mini.
Notez également que l'extrait ci-dessus est placé dans le <head>
du layout afin qu'il soit exécuté dès que possible et avant tout script que la version bureau pourrait avoir. Dans ce cas, la version bureau utilise beaucoup de javascript pour charger beaucoup de contenu, nous ne voulions donc vraiment pas que tout cela se produise sur un téléphone avant que le site ne reconnaisse que l'utilisateur devrait voir la version mobile du site.
Sur chaque page mobile, nous devons faire ceci (à partir de `app/views/layout/application.mobile.erb):
<script>
var device_cookie = cookie.get('device'),
cookiesEnabled = cookie.enabled();
if (cookiesEnabled && device_cookie == 'desktop') {
window.location.reload(true);
}
</script>
Ceci est dû au fait que les appareils mobiles mettent en cache les pages de manière intensive (ce qui est logique) donc si l'utilisateur a changé d'appareil, nous devons nous assurer d'envoyer ce cookie mis à jour au serveur même si l'URL n'a pas changé (et donc le cache pense qu'il s'agit de la même page à servir). Le true
dans l'appel de fonction reload
indique au navigateur d'ignorer ce qui se trouve dans le cache.
Notez que nous faisons exactement la même chose sur chaque page bureau, sauf pour vérifier si l'utilisateur a changé son appareil en 'mobile'
.
Détection de l'appareil à /get_device
(app/views/home/get_device.html)
<script>
function isMobile(){
var MOBILE_USER_AGENTS = 'palm|blackberry|nokia|phone|midp|mobi|symbian|chtml|ericsson|minimo|' +
'audiovox|motorola|samsung|telit|upg1|windows ce|ucweb|astel|plucker|' +
'x320|x240|j2me|sgh|portable|sprint|docomo|kddi|softbank|android|mmp|' +
'pdxgw|netfront|xiino|vodafone|portalmmm|sagem|mot-|sie-|ipod|up\\.b|' +
'webos|amoi|novarra|cdm|alcatel|pocket|ipad|iphone|mobileexplorer|' +
'mobile|zune',
mobile_regex = new RegExp(MOBILE_USER_AGENTS, "i"