Comment faire un SPA SEO crawlable?
J'ai travaillé sur comment faire un SPA crawlable par google basé sur google instructions. Même si il y a bien quelques explications générales je ne pouvais pas trouver n'importe où une plus complète, étape par étape tutoriel avec des exemples réels. Après avoir fini ce que je tiens à partager ma solution, afin que les autres aussi s'en servir et éventuellement l'améliorer.
Je suis à l'aide de MVC
avec Webapi
contrôleurs, et Phantomjs sur le côté serveur, et Durandal sur le côté client push-state
activé; j'utilise aussi Breezejs de données client-serveur d'interaction, tout ce que je recommande fortement, mais je vais essayer de donner une explication qui va aussi aider les gens à utiliser d'autres plates-formes.
- concernant le "hors sujet" - une application web programmeur doit trouver un moyen de rendre son application crawlable pour le RÉFÉRENCEMENT, c'est une exigence de base sur le web. Ce n'est pas sur la programmation en soi, mais il est pertinent pour le sujet de la "pratique" relève des problèmes qui sont propres à la programmation de la profession" comme décrit dans la stackoverflow.com/help/on-topic. C'est un problème pour beaucoup de programmeurs aucune solution claire sur l'ensemble du web. J'espérais pour aider les autres et a investi des heures à simplement décrire ici, l'obtention de points négatifs n'est certainement pas à me motiver pour aider à nouveau.
- Si l'accent est mis sur la programmation et pas d'huile de serpent/le secret de la sauce SEO vaudou/spam alors il peut être parfaitement d'actualité. Nous avons également, comme l'réponses où ils ont le potentiel pour être utile aux futurs lecteurs de longue durée. Cette question & réponse de la paire semble passer à la fois de ces tests. (Certains des détails d'arrière-plan peut de la chair, la question de mieux plutôt que d'être introduite dans la réponse, mais c'est assez mineur)
- +1 pour réduire vers le bas de votes. Peu importe si q/a serait mieux adapté que le billet de blog, la question pertinente est de Durandal et la réponse est bien documenté.
- Je suis d'accord que le RÉFÉRENCEMENT est une partie importante de nos jours de la part des développeurs tous les jours la vie et doit certainement être considéré comme un thème dans stackoverflow!
- Autre que la mise en œuvre de l'ensemble du processus vous-même, vous pouvez essayer de SnapSearch snapsearch.io qui, fondamentalement, répond à ce problème en tant que service.
Vous devez vous connecter pour publier un commentaire.
Avant de commencer, assurez-vous de comprendre ce que google nécessite, en particulier l'utilisation de jolie et laid Url. Voyons maintenant la mise en œuvre:
Côté Client
Sur le côté client, vous n'avez qu'une seule page html qui interagit avec le serveur de manière dynamique via des appels AJAX. c'est ce SPA est d'environ. Tous les
a
balises dans le côté client sont créés dynamiquement dans mon application, nous allons voir plus tard comment faire de ces liens visibles à google bot sur le serveur. Chacun de cesa
balise doit être en mesure d'avoir unpretty URL
dans lehref
étiquette de manière à ce que google bot va analyser ça. Vous ne voulez pas lehref
partie pour être utilisé lorsque le client clique sur elle (même si vous ne voulez que le serveur afin de pouvoir l'analyser, nous le verrons plus tard), car on ne peut pas vouloir une nouvelle page se charge, uniquement pour faire un appel AJAX obtenir certaines données à afficher dans la partie de la page et de modifier l'URL via javascript (par exemple à l'aide de HTML5pushstate
ou avecDurandaljs
). Donc, nous avons à la fois unehref
attribut de google ainsi que suronclick
qui fait le travail lorsque l'utilisateur clique sur le lien. Maintenant, depuis que j'utilisepush-state
je ne veux pas de#
sur l'URL, donc un typiquea
balise peut ressembler à ceci:<a href="http://www.xyz.com/#!/category/subCategory/product111" onClick="loadProduct('category','subCategory','product111')>see product111...</a>
"catégorie" et "sous-catégorie" aurait probablement d'autres expressions, telles que "la communication" et "téléphones" ou "ordinateurs" et "portables" pour l'un des appareils électroménagers en magasin. Évidemment, il y aurait beaucoup de différentes catégories et sous-catégories. Comme vous pouvez le voir, le lien est directement à la catégorie, sous-catégorie et le produit, et non pas comme des paramètres à une fonction spécifique de "stocker" de la page de
http://www.xyz.com/store/category/subCategory/product111
. C'est parce que je préfère le plus court et le plus simple des liens. Cela implique que j'ai il n'y aura pas une catégorie avec le même nom que l'un de mes "pages", c'est à dire "au sujet de".Je ne vais pas aller dans la façon de charger les données via AJAX (le
onclick
partie), rechercher sur google, il y a beaucoup de bonnes explications. La seule chose importante ici que je veux mentionner, c'est que lorsque l'utilisateur clique sur ce lien, je veux que l'URL dans le navigateur de la manière suivante:http://www.xyz.com/category/subCategory/product111
. Et c'est l'URL n'est pas envoyé au serveur ! rappelez-vous, c'est un SPA où toutes les interactions entre le client et le serveur se fait via AJAX, pas de liens du tout! toutes les "pages" sont mis en œuvre sur le côté client, et les différentes URL de ne pas faire un appel vers le serveur (le serveur n'a besoin de savoir comment gérer ces URLs dans le cas où ils sont utilisés comme liens externes à partir d'un autre site sur votre site, nous le verrons plus tard sur le côté serveur de la partie). Maintenant, c'est géré à merveille par Durandal. Je le recommande vivement, mais vous pouvez aussi sauter cette partie si vous préférez d'autres technologies. Si vous choisissez, et vous êtes également à l'aide de MS Visual Studio Express 2012 pour le Web, comme moi, vous pouvez installer le Durandal Starter Kit, et là, dansshell.js
, utiliser quelque chose comme ceci:Il ya quelques choses importantes à remarquer ici:
route:''
) est pour l'URL qui n'a pas de données supplémentaires en elle, c'est à direhttp://www.xyz.com
. Dans cette page vous chargez des données générales à l'aide d'AJAX. Il y aura peut-être pasa
balises à tous dans cette page. Vous souhaitez ajouter la balise suivante, de sorte que google bot de savoir quoi faire avec elle:<meta name="fragment" content="!">
. Cette balise va faire google bot transformer l'URL dewww.xyz.com?_escaped_fragment_=
que nous allons voir plus tard.mapUnknownRoutes
vient dans. Il cartes de ces inconnus itinéraires de "stocker" de l'itinéraire et supprime également toutes les '!' partir de l'URL dans le cas où c'est unpretty URL
généré par google moteur de recherche. "Stocker" de l'itinéraire prend l'info dans le "fragment" la propriété et fait l'appel AJAX pour obtenir les données, de les afficher et de modifier l'URL en local. Dans mon application, je n'ai pas de charger une page différente pour chaque appel; j'ai seulement changer la partie de la page où ces données sont pertinentes et aussi changer l'URL en local.pushState:true
qui indique Durandal utiliser push état Url.C'est tout ce dont nous avons besoin dans le côté client. Il peut être mis en œuvre également avec hachés Url (dans Durandal, vous retirez simplement la
pushState:true
pour ça). La partie la plus complexe (au moins pour moi...) a été la partie serveur:Côté Serveur
Je suis en utilisant
MVC 4.5
sur le côté serveur avecWebAPI
contrôleurs. Le serveur doit gérer 3 types d'Url: ceux générés par google - deuxpretty
etugly
et aussi un 'simple' de l'URL avec le même format que celui qui apparaît dans le navigateur du client. Voyons comment faire cela:Des URLs propres et "simples" sont d'abord interprétée par le serveur comme s'il essayait de référence inexistante du contrôleur. Le serveur voit quelque chose comme
http://www.xyz.com/category/subCategory/product111
et recherche un contrôleur nommé "catégorie". Ainsi, dansweb.config
j'ai ajouter la ligne suivante pour rediriger ces à une erreur de manipulation de contrôleur:Maintenant, cela transforme l'URL à quelque chose comme:
http://www.xyz.com/Error?aspxerrorpath=/category/subCategory/product111
. Je veux que l'URL sera envoyé au client qui va charger les données via AJAX, donc, l'astuce ici est d'appeler la valeur par défaut 'index' contrôleur comme si pas référence à n'importe quel contrôleur; je ne que par ajout un hash de l'URL avant tout la "catégorie" et "sous-catégorie "paramètres"; le haché URL ne nécessite pas de contrôleur spécial à l'exception de la valeur par défaut 'index' et le contrôleur des données est envoyé au client qui enlève le hachage et utilise les informations après le hachage pour charger les données via AJAX. Ici est le gestionnaire d'erreur du contrôleur de code:Mais ce que sur le Laid Url? Elles sont créées par google bot et doit retourner HTML qui contient toutes les données que l'utilisateur voit dans le navigateur. Pour cela, j'utilise phantomjs. Phantom est un navigateur sans faire ce que le navigateur est en train de faire sur le côté client, mais sur le côté serveur. En d'autres termes, le fantôme ne sait pas (entre autres choses) comment faire pour obtenir une page web via une URL, de l'analyser, y compris l'exécution de tout le code javascript dans celui-ci (ainsi que l'obtention de données via des appels AJAX), et vous redonner le HTML qui reflète les DOM. Si vous êtes à l'aide de MS Visual Studio Express vous nombreux à installer fantôme via ce lien.
Mais d'abord, quand un vilain URL est envoyée au serveur, nous devons rattraper; Pour cela, j'ai ajouté à la 'App_start dossier le fichier suivant:
Cela s'appelle de " filterConfig.cs' aussi dans "App_start':
Comme vous pouvez le voir, 'AjaxCrawlableAttribute" les itinéraires laid Url à un contrôleur nommé "HtmlSnapshot", et voici ce contrôleur:
Les associés
view
est très simple, il suffit d'une seule ligne de code:@Html.Raw( ViewBag.result )
Comme vous pouvez le voir dans le contrôleur, le fantôme charge un fichier javascript nommé
createSnapshot.js
sous un dossier que j'ai créé appeléseo
. Voici ce fichier javascript:Je tiens d'abord à remercier Thomas Davis de la page où j'ai obtenu le code de base à partir :-).
Vous remarquerez quelque chose de bizarre ici: phantom conserve re-chargement de la page jusqu'à ce que le
checkLoaded()
fonction renvoie la valeur true. Pourquoi est-ce? c'est parce que mon spécifiques SPA, plusieurs appel AJAX pour obtenir toutes les données et de les placer dans les DOM sur ma page, et le fantôme ne peut pas savoir quand tous les appels ont terminée avant de retourner me HTML reflet de la DOM. Ce que j'ai fait ici est après le dernier appel AJAX-je ajouter un<span id='compositionComplete'></span>
, de sorte que, si cette balise existe je sais que le DOM est terminé. Je fais cela en réponse à la Durandal decompositionComplete
événement, voir ici pour plus d'. Si cela ne se produit pas dans les 10 secondes que j'ai abandonner (il faut prendre seulement une seconde à ce que la plupart des). Le HTML retourné contient tous les liens que l'utilisateur voit dans le navigateur. Le script ne fonctionnera pas correctement car le<script>
les balises qui n'existe pas dans le code HTML de capture instantanée ne font pas référence à l'URL. Ceci peut être changé dans le code javascript, fantôme de fichier, mais je ne pense pas que c'est necassary parce que le HTML snapshort est seulement utilisé par google pour obtenir laa
liens et de ne pas exécuter javascript; ces liens ne référence à une URL jolie, et si fait, si vous essayez de voir l'instantané HTML dans un navigateur, vous obtiendrez des erreurs javascript, mais tous les liens ne fonctionnent pas correctement et vous orienter vers le serveur une fois de plus avec une jolie URL de temps à apprendre le travail entièrement la page.Ce qu'il est. Maintenant que le serveur de savoir comment gérer à la fois beau et laid Url, avec push-de l'état activé à la fois serveur et client. Tous les vilains, les Url sont traités de la même manière à l'aide de fantôme, il n'ya donc pas besoin de créer un contrôleur séparé pour chaque type d'appel.
Une chose que vous pourriez préférer le changement n'est pas de faire une catégorie/sous-catégorie/produit d'appel, mais pour ajouter un "magasin" de sorte que le lien ressemblera à quelque chose comme:
http://www.xyz.com/store/category/subCategory/product111
. Cela permettra d'éviter le problème dans ma solution que toutes les Url non valide sont traités comme s'ils sont en fait les appels à l'index du contrôleur, et je suppose que ceux-ci peuvent être traitées puis à l'intérieur de "stocker" contrôleur sans l'ajout de laweb.config
je l'ai montré ci-dessus.Google est maintenant capable de rendre la SPA de pages:
La dépréciation de notre processus d'exploration AJAX
Voici un lien vers un screencast-enregistrement à partir de mon Ember.js la Formation de la classe, j'ai organisé à Londres, le 14 août. Elle définit une stratégie à la fois pour l'application côté client et pour vous application côté serveur, ainsi que donne une démonstration de la façon dont la mise en œuvre de ces fonctionnalités vous fournir votre code JavaScript Simple-Page-Application à la dégradation gracieuse, même pour les utilisateurs avec JavaScript désactivé.
Il utilise PhantomJS pour faciliter l'analyse de votre site web.
En bref, les étapes sont les suivantes:
Une fois que cette étape est terminée, c'est à votre backend pour servir la statique-la version de votre code HTML dans le cadre de la noscript tag sur cette page. Cela permettra à Google et autres moteurs de recherche de parcourir chaque page sur votre site web, même si votre application est à l'origine une seule page-app.
Lien vers la vidéo avec tous les détails:
http://www.devcasts.io/p/spas-phantomjs-and-seo/#
Vous pouvez utiliser ou créer votre propre service de pré-rendu de votre SPA avec le service appelé pré-rendu. Vous pouvez le vérifier sur son site pré-rendu.io et sur son projet github (Il utilise PhantomJS et il renderize votre site web pour vous).
Il est très facile à démarrer avec. Vous n'avez qu'à rediriger les robots des demandes de service et ils recevront le rendu html.
Vous pouvez utiliser http://sparender.com/ qui permet une Seule Page Applications pour être analysées correctement.