Ich habe daran gearbeitet, wie ein SPA mithilfe der Anweisungen von Google von Google gecrawlt werden kann . Obwohl es einige allgemeine Erklärungen gibt, konnte ich nirgendwo ein gründlicheres Schritt-für-Schritt-Tutorial mit tatsächlichen Beispielen finden. Nachdem ich dies abgeschlossen habe, möchte ich meine Lösung teilen, damit auch andere sie nutzen und möglicherweise weiter verbessern können.
Ich verwende MVC
mit Webapi
Controllern und Phantomjs auf der Serverseite und Durandal auf der Clientseite mit push-state
aktiviert; Ich verwende Breezejs auch für die Client-Server-Dateninteraktion, die ich dringend empfehle, aber ich werde versuchen, eine ausreichend allgemeine Erklärung zu geben, die auch Menschen hilft, andere Plattformen zu verwenden.
143
Antworten:
Bevor Sie beginnen, stellen Sie bitte sicher, dass Sie verstehen, was Google benötigt , insbesondere die Verwendung hübscher und hässlicher URLs. Nun sehen wir uns die Implementierung an:
Client-Seite
Auf der Clientseite haben Sie nur eine einzige HTML-Seite, die über AJAX-Aufrufe dynamisch mit dem Server interagiert. Darum geht es bei SPA. Alle
a
Tags auf der Clientseite werden dynamisch in meiner Anwendung erstellt. Wir werden später sehen, wie diese Links für Googles Bot auf dem Server sichtbar gemacht werden. Jedes diesera
Tags muss in der Lage sein, einpretty URL
imhref
Tag zu haben, damit der Google-Bot es crawlen kann. Sie möchten nicht, dass dashref
Teil verwendet wird, wenn der Client darauf klickt (obwohl Sie möchten, dass der Server es analysieren kann, werden wir das später sehen), da wir möglicherweise nicht möchten, dass eine neue Seite geladen wird. Nur um einen AJAX-Aufruf zu tätigen und einige Daten in einem Teil der Seite anzuzeigen und die URL über Javascript zu ändern (z. B. mit HTML5pushstate
oder mitDurandaljs
). Also haben wir beide einehref
Attribut für Google sowie das, aufonclick
das der Job ausgeführt wird, wenn der Benutzer auf den Link klickt. Dapush-state
ich jetzt keine#
URL verwenden möchte , kann ein typischesa
Tag folgendermaßen aussehen:<a href="http://www.xyz.com/#!/category/subCategory/product111" onClick="loadProduct('category','subCategory','product111')>see product111...</a>
"Kategorie" und "Unterkategorie" sind wahrscheinlich andere Ausdrücke wie "Kommunikation" und "Telefone" oder "Computer". und "Laptops" für ein Elektrogerätegeschäft. Offensichtlich würde es viele verschiedene Kategorien und Unterkategorien geben. Wie Sie sehen können, befindet sich der Link direkt auf die Kategorie, Unterkategorie und das Produkt, nicht als zusätzliche Parameter für eine bestimmte "Store" -Seite wie z
http://www.xyz.com/store/category/subCategory/product111
. Das liegt daran, dass ich kürzere und einfachere Links bevorzuge. Dies bedeutet, dass es keine Kategorie mit demselben Namen wie eine meiner "Seiten" geben wird, dh "Ich werde nicht darauf eingehen, wie man die Daten über AJAX (das
onclick
Teil) lädt , sie auf Google sucht, es gibt viele gute Erklärungen. Das einzig Wichtige, das ich hier erwähnen möchte, ist, dass wenn der Benutzer auf diesen Link klickt, die URL im Browser folgendermaßen aussehen soll:http://www.xyz.com/category/subCategory/product111
. Und diese URL wird nicht an den Server gesendet! Denken Sie daran, dies ist ein SPA, in dem die gesamte Interaktion zwischen dem Client und dem Server über AJAX erfolgt, überhaupt keine Links! Alle "Seiten" werden auf der Clientseite implementiert, und die unterschiedliche URL ruft den Server nicht auf (der Server muss wissen, wie mit diesen URLs umgegangen wird, wenn sie als externe Links von einer anderen Site zu Ihrer Site verwendet werden.) Wir werden das später auf der Serverseite sehen. Nun, das wird von Durandal wunderbar gehandhabt. Ich kann es nur empfehlen, aber Sie können diesen Teil auch überspringen, wenn Sie andere Technologien bevorzugen. Wenn Sie sich dafür entscheiden und wie ich auch MS Visual Studio Express 2012 für das Web verwenden, können Sie das Durandal Starter Kit installieren und dort etwa Folgendesshell.js
verwenden:Hier sind einige wichtige Dinge zu beachten:
route:''
) ist für die URL, die keine zusätzlichen Daten enthält, dhttp://www.xyz.com
. H. Auf dieser Seite laden Sie allgemeine Daten mit AJAX. Aufa
dieser Seite befinden sich möglicherweise überhaupt keine Tags. Sie sollten das folgende Tag hinzufügen, damit der Google-Bot weiß, was damit zu tun ist :<meta name="fragment" content="!">
. Mit diesem Tag transformiert Googles Bot die URL, zuwww.xyz.com?_escaped_fragment_=
der wir später sehen werden.mapUnknownRoutes
kommt es ins Spiel. Es ordnet diese unbekannten Routen der 'Store'-Route zu und entfernt auch alle'! ' von der URL, falls es sich um einepretty URL
von Googles Suchmaschine generierte handelt. Die 'store'-Route nimmt die Informationen in der' fragment'-Eigenschaft und führt den AJAX-Aufruf aus, um die Daten abzurufen, anzuzeigen und die URL lokal zu ändern. In meiner Anwendung lade ich nicht für jeden solchen Aufruf eine andere Seite. Ich ändere nur den Teil der Seite, auf dem diese Daten relevant sind, und ändere auch die URL lokal.pushState:true
was Durandal anweist, Push-Status-URLs zu verwenden.Dies ist alles, was wir auf der Client-Seite brauchen. Es kann auch mit Hash-URLs implementiert werden (in Durandal entfernen Sie einfach die
pushState:true
dafür). Der komplexere Teil (zumindest für mich ...) war der Serverteil:Serverseite
Ich benutze
MVC 4.5
auf der Serverseite mitWebAPI
Controllern. Der Server muss tatsächlich drei Arten von URLs verarbeiten: die von Google generierten - sowohlpretty
alsugly
auch eine "einfache" URL mit demselben Format wie die im Browser des Clients angezeigte. Schauen wir uns an, wie das geht:Hübsche und einfache URLs werden vom Server zunächst so interpretiert, als würde versucht, auf einen nicht vorhandenen Controller zu verweisen. Der Server sieht so etwas wie
http://www.xyz.com/category/subCategory/product111
und sucht nach einem Controller namens 'category'. Daherweb.config
füge ich die folgende Zeile hinzu, um diese an einen bestimmten Fehlerbehandlungscontroller umzuleiten:Dadurch wird die URL in Folgendes umgewandelt :
http://www.xyz.com/Error?aspxerrorpath=/category/subCategory/product111
. Ich möchte, dass die URL an den Client gesendet wird, der die Daten über AJAX lädt. Der Trick hier besteht darin, den Standard-Index-Controller so aufzurufen, als würde er nicht auf einen Controller verweisen. Dazu füge ich der URL vor allen Parametern 'category' und 'subCategory' einen Hash hinzu . Die Hash-URL erfordert keinen speziellen Controller außer dem Standard-Index-Controller. Die Daten werden an den Client gesendet, der dann den Hash entfernt und die Informationen nach dem Hash verwendet, um die Daten über AJAX zu laden. Hier ist der Code des Fehlerbehandlungs-Controllers:Aber was ist mit den hässlichen URLs ? Diese werden vom Google-Bot erstellt und sollten einfachen HTML-Code zurückgeben, der alle Daten enthält, die der Benutzer im Browser sieht. Dafür benutze ich Phantomjs . Phantom ist ein kopfloser Browser, der das tut, was der Browser auf der Clientseite tut - aber auf der Serverseite. Mit anderen Worten, Phantom weiß (unter anderem), wie man eine Webseite über eine URL abruft, analysiert, einschließlich des gesamten darin enthaltenen Javascript-Codes (sowie des Abrufs von Daten über AJAX-Aufrufe), und gibt Ihnen den reflektierten HTML-Code zurück das DOM. Wenn Sie MS Visual Studio Express verwenden, möchten viele Phantom über diesen Link installieren .
Aber zuerst, wenn eine hässliche URL an den Server gesendet wird, müssen wir sie abfangen. Zu diesem Zweck habe ich dem Ordner 'App_start' die folgende Datei hinzugefügt:
Dies wird von 'filterConfig.cs' auch in 'App_start' aufgerufen:
Wie Sie sehen können, leitet 'AjaxCrawlableAttribute' hässliche URLs an einen Controller mit dem Namen 'HtmlSnapshot' weiter. Hier ist dieser Controller:
Das zugehörige
view
ist sehr einfach, nur eine Codezeile:@Html.Raw( ViewBag.result )
Wie Sie im Controller sehen können, lädt Phantom eine Javascript-Datei, die
createSnapshot.js
unter einem von mir erstellten Ordner namens benannt istseo
. Hier ist diese Javascript-Datei:Ich möchte mich zuerst bei Thomas Davis für die Seite bedanken, auf der ich den Basiscode erhalten habe :-).
Sie werden hier etwas Seltsames bemerken: Phantom lädt die Seite so lange neu, bis die
checkLoaded()
Funktion true zurückgibt. Warum ist das so? Dies liegt daran, dass mein spezifisches SPA mehrere AJAX-Aufrufe ausführt, um alle Daten abzurufen und im DOM auf meiner Seite zu platzieren. Das Phantom kann nicht wissen, wann alle Aufrufe abgeschlossen sind, bevor es mir die HTML-Reflektion des DOM zurückgibt. Was ich hier getan habe, ist<span id='compositionComplete'></span>
, dass ich nach dem letzten AJAX-Aufruf ein hinzufüge , sodass ich weiß, dass das DOM abgeschlossen ist, wenn dieses Tag vorhanden ist. Ich mache das als Reaktion auf DurandalscompositionComplete
Ereignis, siehe hierfür mehr. Wenn dies nicht innerhalb von 10 Sekunden geschieht, gebe ich auf (es sollte höchstens eine Sekunde dauern). Der zurückgegebene HTML-Code enthält alle Links, die der Benutzer im Browser sieht. Das Skript funktioniert nicht ordnungsgemäß, da die<script>
im HTML-Snapshot vorhandenen Tags nicht auf die richtige URL verweisen. Dies kann auch in der Javascript-Phantomdatei geändert werden, aber ich denke nicht, dass dies notwendig ist, da der HTML-Snapshort nur von Google verwendet wird, um diea
Links abzurufen und kein Javascript auszuführen. diese Links tun Bezug ziemlich URL, und wenn die Tat, wenn Sie versuchen , das HTML - Snapshot in einem Browser zu sehen, werden Sie JavaScript - Fehler , aber alle Links bekommen ordnungsgemäß funktionieren und Sie auf den Server direkt wieder mit einem hübschen URL dieses Mal die voll funktionsfähige Seite bekommen.Das ist es. Jetzt weiß der Server, wie man mit hübschen und hässlichen URLs umgeht, wobei der Push-Status sowohl auf dem Server als auch auf dem Client aktiviert ist. Alle hässlichen URLs werden mit Phantom gleich behandelt, sodass für jeden Anruftyp kein separater Controller erstellt werden muss.
Eine Sache, die Sie vielleicht lieber ändern möchten, ist nicht, einen allgemeinen Aufruf von "Kategorie / Unterkategorie / Produkt" zu tätigen, sondern einen "Shop" hinzuzufügen, damit der Link ungefähr so aussieht :
http://www.xyz.com/store/category/subCategory/product111
. Dadurch wird das Problem in meiner Lösung vermieden, dass alle ungültigen URLs so behandelt werden, als würden sie tatsächlich an den 'Index'-Controller aufgerufen, und ich nehme an, dass diese dann innerhalb des' Store'-Controllers behandelt werden können, ohne dass dieweb.config
oben gezeigte hinzugefügt wird .quelle
Google kann jetzt SPA-Seiten rendern: Unser AJAX-Crawling-Schema wird abgelehnt
quelle
Hier ist ein Link zu einer Screencast-Aufnahme aus meiner Ember.js-Schulungsklasse, die ich am 14. August in London veranstaltet habe. Es beschreibt eine Strategie sowohl für Ihre clientseitige Anwendung als auch für Ihre serverseitige Anwendung und zeigt live, wie die Implementierung dieser Funktionen Ihrer JavaScript-Single-Page-App auch für Benutzer mit deaktiviertem JavaScript eine angemessene Verschlechterung verleiht .
Es verwendet PhantomJS, um das Crawlen Ihrer Website zu unterstützen.
Kurz gesagt, die erforderlichen Schritte sind:
Sobald dieser Schritt abgeschlossen ist, liegt es an Ihrem Backend, die statische Version Ihres HTML-Codes als Teil des Noscript-Tags auf dieser Seite bereitzustellen. Auf diese Weise können Google und andere Suchmaschinen jede einzelne Seite Ihrer Website crawlen, obwohl Ihre App ursprünglich eine Einzelseiten-App ist.
Link zum Screencast mit allen Details:
http://www.devcasts.io/p/spas-phantomjs-and-seo/#
quelle
Sie können Ihren eigenen Dienst zum Vorrendern Ihres SPA mit dem Dienst Prerender verwenden oder erstellen. Sie können es auf seiner Website prerender.io und in seinem Github-Projekt überprüfen (es verwendet PhantomJS und rendert Ihre Website für Sie).
Es ist sehr einfach zu beginnen. Sie müssen nur Crawler-Anforderungen an den Dienst umleiten, und sie erhalten das gerenderte HTML.
quelle
Sie können http://sparender.com/ verwenden , damit einzelne Seitenanwendungen korrekt gecrawlt werden können.
quelle