Pracowałem nad tym, jak umożliwić indeksowanie SPA przez Google na podstawie instrukcji Google . Mimo że istnieje kilka ogólnych wyjaśnień, nie mogłem nigdzie znaleźć dokładniejszego samouczka krok po kroku z rzeczywistymi przykładami. Po skończeniu tego chciałbym podzielić się moim rozwiązaniem, aby inni również mogli z niego skorzystać i ewentualnie dalej je ulepszać.
Używam MVC
z Webapi
kontrolerami i Phantomjs po stronie serwera i Durandal po stronie klienta z push-state
włączoną; Używam także Breezejs do interakcji danych klient-serwer, które zdecydowanie polecam, ale postaram się podać wystarczająco ogólne wyjaśnienie, które pomoże również osobom korzystającym z innych platform.
143
Odpowiedzi:
Zanim zaczniesz, upewnij się, że rozumiesz, czego wymaga Google , zwłaszcza dotyczące używania ładnych i brzydkich adresów URL. Teraz zobaczmy implementację:
Strona klienta
Po stronie klienta masz tylko jedną stronę html, która dynamicznie współdziała z serwerem za pośrednictwem wywołań AJAX. o to chodzi w SPA. Wszystkie
a
tagi po stronie klienta są tworzone dynamicznie w mojej aplikacji, później zobaczymy, jak sprawić, by te linki były widoczne dla bota Google na serwerze. Każdy takia
tag musi mieć możliwość umieszczeniapretty URL
whref
tagu znaku, aby robot Google go zaindeksował. Nie chcesz, abyhref
część była używana, gdy klient ją kliknie (nawet jeśli chcesz, aby serwer mógł ją przeanalizować, zobaczymy to później), ponieważ możemy nie chcieć załadować nowej strony, tylko po to, aby wykonać wywołanie AJAX, uzyskując dane do wyświetlenia w części strony i zmienić adres URL za pomocą javascript (np. używając HTML5pushstate
lub withDurandaljs
). Tak więc mamy oba plikihref
atrybut dla google, a takżeonclick
który wykonuje zadanie, gdy użytkownik kliknie link. Teraz, ponieważ używampush-state
, nie chcę żadnego#
w adresie URL, więc typowya
tag może wyglądać tak:<a href="http://www.xyz.com/#!/category/subCategory/product111" onClick="loadProduct('category','subCategory','product111')>see product111...</a>
„kategoria” i „podkategoria” to prawdopodobnie inne wyrażenia, takie jak „komunikacja” i „telefony” lub „komputery” oraz „laptopy” dla sklepu z urządzeniami elektrycznymi. Oczywiście byłoby wiele różnych kategorii i podkategorii. Jak widać, link prowadzi bezpośrednio do kategorii, podkategorii i produktu, a nie jako dodatkowe parametry do określonej strony sklepu, takiej jak
http://www.xyz.com/store/category/subCategory/product111
. Dzieje się tak, ponieważ wolę krótsze i prostsze linki. Oznacza to, że nie będzie kategorii o takiej samej nazwie jak jedna z moich „stron”, tj. „Nie będę się zagłębiał w ładowanie danych przez AJAX (
onclick
część), przeszukuję go w google, jest wiele dobrych wyjaśnień. Jedyną ważną rzeczą, o której chcę tutaj wspomnieć, jest to, że kiedy użytkownik kliknie ten link, chcę, aby adres URL w przeglądarce wyglądał następująco:http://www.xyz.com/category/subCategory/product111
. A to adres URL nie jest wysyłany do serwera! pamiętaj, jest to SPA, w którym cała interakcja między klientem a serwerem odbywa się za pośrednictwem AJAX, żadnych łączy! wszystkie `` strony '' są zaimplementowane po stronie klienta, a inny adres URL nie wywołuje serwera (serwer musi wiedzieć, jak obsługiwać te adresy URL, jeśli są używane jako linki zewnętrzne z innej witryny do Twojej witryny, zobaczymy to później w części po stronie serwera). Teraz Durandal wspaniale sobie z tym radzi. Gorąco polecam, ale możesz też pominąć tę część, jeśli wolisz inne technologie. Jeśli go wybierzesz, a także używasz MS Visual Studio Express 2012 for Web, tak jak ja, możesz zainstalować zestaw startowy Durandal , a tam, w programieshell.js
, użyć czegoś takiego:Należy tu zwrócić uwagę na kilka ważnych rzeczy:
route:''
) dotyczy adresu URL, który nie zawiera żadnych dodatkowych danych, tjhttp://www.xyz.com
. Na tej stronie ładujesz ogólne dane za pomocą AJAX. W rzeczywistościa
na tej stronie może nie być żadnych tagów. Będziemy chcieli, aby dodać następujący tag tak że Google jest bot będzie wiedział, co z nim zrobić:<meta name="fragment" content="!">
. Ten tag sprawi, że bot google przekształci adres URL, dowww.xyz.com?_escaped_fragment_=
którego zobaczymy później.mapUnknownRoutes
pojawia się. Mapuje te nieznane trasy na trasę „sklepu”, a także usuwa wszelkie „!” z adresu URL, jeśli jestpretty URL
wygenerowany przez wyszukiwarkę Google. Trasa „store” pobiera informacje z właściwości „fragment” i wykonuje wywołanie AJAX w celu pobrania danych, wyświetlenia ich i lokalnej zmiany adresu URL. W mojej aplikacji nie ładuję innej strony dla każdego takiego połączenia; Zmieniam tylko część strony, w której te dane są istotne, a także zmieniam lokalnie adres URL.pushState:true
co instruuje Durandala, aby używał adresów URL stanu wypychania.To wszystko, czego potrzebujemy po stronie klienta. Można to zaimplementować również z zahaszowanymi adresami URL (w Durandal po prostu usuwasz w tym
pushState:true
celu). Bardziej złożoną częścią (przynajmniej dla mnie ...) była część serwerowa:Po stronie serwera
Używam
MVC 4.5
po stronie serwera zWebAPI
kontrolerami. Serwer faktycznie musi obsługiwać 3 rodzaje adresów URL: te generowane przez Google - zarównopretty
augly
, a także „prosty” URL z takim samym formacie jak ten, który pojawia się w przeglądarce klienta. Zobaczmy, jak to zrobić:Ładne adresy URL i „proste” są najpierw interpretowane przez serwer tak, jakby próbowały odwołać się do nieistniejącego kontrolera. Serwer widzi coś podobnego
http://www.xyz.com/category/subCategory/product111
i szuka kontrolera o nazwie „kategoria”. Więcweb.config
dodaję następujący wiersz, aby przekierować je do określonego kontrolera obsługi błędów:Teraz, to przekształca URL do czegoś takiego:
http://www.xyz.com/Error?aspxerrorpath=/category/subCategory/product111
. Chcę, aby adres URL był wysyłany do klienta, który będzie ładował dane przez AJAX, więc sztuczka polega na wywołaniu domyślnego kontrolera „indeksu”, jakby nie odwoływał się do żadnego kontrolera; Robię to, dodając skrót do adresu URL przed wszystkimi parametrami „category” i „subCategory”; zaszyfrowany adres URL nie wymaga żadnego specjalnego kontrolera z wyjątkiem domyślnego kontrolera „indeksu”, a dane są wysyłane do klienta, który następnie usuwa hash i używa informacji po hashu do załadowania danych przez AJAX. Oto kod kontrolera obsługi błędów:Ale co z brzydkimi adresami URL ? Są one tworzone przez bota Google i powinny zwracać zwykły kod HTML zawierający wszystkie dane, które użytkownik widzi w przeglądarce. Do tego używam phantomjs . Phantom to przeglądarka bezgłowa, która robi to, co przeglądarka robi po stronie klienta - ale po stronie serwera. Innymi słowy, fantom wie (między innymi), jak uzyskać stronę internetową za pośrednictwem adresu URL, przeanalizować ją, w tym uruchomić cały kod javascript (a także pobrać dane za pośrednictwem wywołań AJAX) i zwrócić kod HTML, który odzwierciedla DOM. Jeśli używasz MS Visual Studio Express, wielu z was chce zainstalować fantom za pomocą tego linku .
Ale najpierw, kiedy brzydki adres URL jest wysyłany do serwera, musimy go przechwycić; W tym celu dodałem do folderu „App_start” następujący plik:
Jest to wywoływane z „filterConfig.cs” również w „App_start”:
Jak widać, „AjaxCrawlableAttribute” kieruje brzydkie adresy URL do kontrolera o nazwie „HtmlSnapshot”, a oto ten kontroler:
Skojarzony
view
jest bardzo prosty, tylko jeden wiersz kodu:@Html.Raw( ViewBag.result )
jak widać w kontrolerze, phantom ładuje plik javascript o nazwie
createSnapshot.js
pod utworzonym przeze mnie folderemseo
. Oto ten plik javascript:Najpierw chciałbym podziękować Thomasowi Davisowi za stronę, z której otrzymałem podstawowy kod :-).
Zauważysz tutaj coś dziwnego: phantom ponownie ładuje stronę, dopóki
checkLoaded()
funkcja nie zwróci true. Dlaczego? Dzieje się tak, ponieważ moje konkretne SPA wykonuje kilka wywołań AJAX, aby pobrać wszystkie dane i umieścić je w DOM na mojej stronie, a fantom nie może wiedzieć, kiedy wszystkie wywołania zostały zakończone, zanim zwróci mi odbicie HTML DOM. To, co tutaj zrobiłem, to po ostatnim wywołaniu AJAX, dodałem a<span id='compositionComplete'></span>
, więc jeśli ten tag istnieje, wiem, że DOM jest zakończony. Robię to w odpowiedzi nacompositionComplete
wydarzenie Durandala , patrz tutajpo więcej. Jeśli tak się nie stanie w ciągu 10 sekund, poddaję się (maksymalnie powinno to zająć tylko sekundę). Zwrócony kod HTML zawiera wszystkie linki, które użytkownik widzi w przeglądarce. Skrypt nie będzie działał poprawnie, ponieważ<script>
tagi, które istnieją w migawce HTML, nie odwołują się do właściwego adresu URL. Można to również zmienić w pliku phantom javascript, ale nie sądzę, aby to było konieczne, ponieważ skrót HTML jest używany tylko przez Google do pobieraniaa
linków, a nie do uruchamiania javascript; Te linki zrobić odwoływać się ładny URL, a jeśli rzeczywistości, jeśli starają się zobaczyć zrzut HTML w przeglądarce, dostaniesz błędy JavaScript, ale wszystkie linki będą działać poprawnie i skieruje cię do serwera po raz kolejny z dość URL tego czasu uzyskanie w pełni działającej strony.To jest to. Teraz serwer wie, jak obsługiwać zarówno ładne, jak i brzydkie adresy URL, z włączonym stanem wypychania zarówno na serwerze, jak i kliencie. Wszystkie brzydkie adresy URL są traktowane w ten sam sposób za pomocą fantomu, więc nie ma potrzeby tworzenia oddzielnego kontrolera dla każdego typu wywołania.
Jedna rzecz może wolisz do zmian nie jest do zwołania walnego 'kategorii / podkategorii / produktu, ale dodać „magazyn”, tak, że związek będzie wyglądać mniej więcej tak:
http://www.xyz.com/store/category/subCategory/product111
. Pozwoli to uniknąć problemu w moim rozwiązaniu, że wszystkie nieprawidłowe adresy URL są traktowane tak, jakby były faktycznie wywołaniami kontrolera „indeksu” i przypuszczam, że można je wtedy obsłużyć w kontrolerze „sklepu” bez dodatku doweb.config
pokazanego powyżej .źródło
Google może teraz renderować strony SPA: wycofujemy nasz schemat indeksowania AJAX
źródło
Oto link do nagrania screencast z moich zajęć szkoleniowych Ember.js, które gościłem w Londynie 14 sierpnia. Przedstawia strategię zarówno dla aplikacji po stronie klienta, jak i dla aplikacji po stronie serwera, a także przedstawia na żywo, w jaki sposób wdrożenie tych funkcji zapewni Twojej aplikacji jednostronicowej JavaScript z gracją degradacji nawet dla użytkowników z wyłączoną obsługą JavaScript .
Używa PhantomJS do pomocy w indeksowaniu Twojej witryny.
Krótko mówiąc, wymagane kroki to:
Po wykonaniu tego kroku backend będzie obsługiwał statyczną wersję kodu HTML jako część tagu noscript na tej stronie. Umożliwi to Google i innym wyszukiwarkom zaindeksowanie każdej strony w Twojej witrynie, nawet jeśli Twoja aplikacja pierwotnie była aplikacją z pojedynczą stroną.
Link do screencasta z pełnymi szczegółami:
http://www.devcasts.io/p/spas-phantomjs-and-seo/#
źródło
Możesz skorzystać lub stworzyć własną usługę prerender swojego SPA z usługą o nazwie prerender. Możesz to sprawdzić na jego stronie prerender.io oraz w jego projekcie na githubie (używa PhantomJS i renderuje twoją stronę dla Ciebie).
Bardzo łatwo jest zacząć. Musisz tylko przekierować żądania robotów do usługi, a one otrzymają wyrenderowany kod HTML.
źródło
Możesz użyć http://sparender.com/, który umożliwia poprawne indeksowanie aplikacji jednostronicowych.
źródło