網頁

RESTful API, SPA, SEO 之三角關係

RESTful API, SPA, SEO 之三角關係

twMVC#28 的討論,有個學員問題一則有趣的問題:在導入 RESTful 架構後,純 JavaScript 執行環境(jQuery, AngularJs, React, ...)的前端要如何做 SEO?

Web資訊流:Database → Model → Server Render → HTML → Browser

SPA資訊流:Database → Model → RESTful API ⇆ JS Framework (Browser)

不論是傳統 ASP、ASP.NET (WebForms)、ASP.NET MVC 等都是以產出 HTML 為最終目標。但前端框架不斷爆發後,原本 Server Render 的角色不斷被 RESTful API 給取代,而前端則是各種框架(jQuery、React、Angular、Vue、...)來操作著 Browser 的 HTML 來進行畫面操作與互動。這類以 JavaScript 為核心的 SPA(Single Page Application) 頁面,對於 SEO(Search Engine Optimization) 而言是非常不友善的。

我本身專注在後端(Backend)且公司主要業務面向也非消費端,雖然知道一二,但回家深入瞭解一番之後,原來還有許多技術面向可以討論,以下就目前收集的到的資料討論。如果有更專精前端(Frontend)與前端 SEO 的朋友,也請不吝指教。

回到 Server Render

利用前端測試框架,如 PhantomJS 去 Render 一個靜態頁面讓搜尋引擎爬蟲去抓取。

整體流程:當讀取頁面的時候,先去判斷是不是 Robot,如果是 Robot,就使用 PhantomJS 餵它已讀取做好的靜態頁面內容。

Browser:走 SPA 資訊流程。 Robot:回應 PhantomJS 產生的靜態頁面。

也就是在請求(request)進入 Server 時,你就要先判斷請求是否為 Robot,再執行對應動作。

有多種方式可以判斷是否為 Robot,例如,

  1. 使用 HttpCapabilitiesBase.Crawler 屬性來判斷。
  2. 使用 User Agent 來判斷,這部份可以查詢如 Robots Database 取得。
  3. 當然,我們的好朋友 Stack Overflow 有更多專業的的解答。

感謝fb網友Kevin Yang補充一套 Google 的解決方案:GoogleChrome/rendertron

使用 Hashtag

這是Google 在 2009 提出的解法,稱 AJAX crawling。簡單說明,SPA 只有一個頁面,頁面的變數主要是透過路由(Route)來驅動。而 SPA 利用 URL 中的 # (Hashtag) 來進行切換。

例如:

index.html?/#!/list/
index.html?/#!/list/1

對於複雜的 SPA 解析對 Google 困難,所以 Google 製定了一個規則:#!,例如:index.html/#!/details/1 則 Google 爬蟲發現 #! 符合則會替換為 _escaped_fragment_ 這個 Google 指定的命名來爬取。而開發者則必須在 index.html?_escaped_fragment_=/detail/1 產生靜態頁面讓 Google 爬蟲抓取。

另外注意,這個架構,必須有 sitemap 的支援,也就是提供給 Google 的 sitemap 必須含 Hashtag 的 URL 即可。不必關心 _escaped_fragment_ 的轉換問題。

如果你的使用端,還是必須兼顧 IE 6/7/8 等瀏灠器,也就是說,對 HTML 5 支援度不完善的用戶端,那麼 Hashtag 是一個可行的架構。

HTML5 History API (IE 9+)

前面提到的 Hashtag 解法,在 2015 年被 Google 自己推翻了,而改用新的 HTML5 History API 來解決。

<a href="/#!/article/1"> 改為 <a href="/article/1">,這個 href 的 URL 與 Hashtag 不同,它會造成轉跳,所以必須使用 JavaScript 攔截,並改用 window.history.pushState() 來設置,例如:

$('#article-list a').on('click', function() {
  var url = $(this).attr('href');
  window.history.pushState(null, null, url);
  return false;
});

其他可能方案

不論何種方案,流程其實大同小異,都是由 Server-Side Render 出獨立頁面讓爬蟲來進行抓取。

網路蠻多人推 prerender.io,它支援多開發平台,例如:ASP.NET,可免費試用。

其他 JS Framework 也大多有自己的解決方案:

小結

在本質上,不論是何種解決,你會發現你都免不了要做 Server Render,產生一份你想給搜尋引擎爬蟲吃進行 HTML,在搜尋引擎爬蟲有能力解析 JavaScript 之前,並無法免除這段工作。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。