首頁 / 程式人雜誌 / 2015年3月號

單頁應用的相關技術與問題

要設計出單頁應用的網站,所採用的技術和傳統網站的設計略有不同,通常一個單頁應用會採用下列技術實作。

  1. 使用 AJAX 或 web socket 動態地從伺服器端撈取資料,或者將資料傳送給伺服器儲存。
  2. 為了不移動到全新網頁,但是卻可以透過上一頁或下一頁來進行網頁歷史操作,可能會採用下列兩種解決方式:
    • 採用 <網址>#<書籤> 的方式設計『內部連結』,並動態的更新文件的內容與標題。
    • 透過 HTML5 的 pushState 與 popState 進行動態連結置換呈現動作 (但是並不會真正換頁)。

透過上述的方式,我們可以設計出互動性很好的單頁應用,不過這種設計方式通常也會有一些缺點。

其中一個重要的缺陷是,搜尋引擎 (像是 google )通常沒辦法搜尋到那些單頁應用的網頁內容。

這個缺陷非常的嚴重,如果沒有辦法解決,很可能會迫使很多網站設計者放棄單頁應用!

但是,這個問題並沒有辦法很容易地解決,因為需要搜尋引擎與網站設計者雙方的配合才行。

為了解決這個問題, google 曾經提出了一個稱為 hashbang 的解決方法,其方法是要求那些以 <網址>#<書籤> 方式設計的單頁應用,如果想要讓 google 可以搜到該頁內容的話,就必須要在書籤的前面加上一個 ! 符號,變成 <網址>#!<書籤> 的格式,以便告知 google 該連結其實具有『對應的單頁』,而那些對應的單頁必須放在 <網址>?_excaped_fragment_=<書籤> 這樣的一個網址中。 (補充:之所以叫做 hashbang 是因為英語世界裡的 # 符號稱為 hash,而 ! 符號念為 bang,因此這個技術就被稱為 hash bang 了)。

換言之,伺服器必須有兩套回應方式,一套是『單頁應用』的回應方式,另一套是『傳統的回應方式』,在『單頁應用版』( <網址>#!<書籤>)上你可以採用 AJAX 動態地向伺服器取得資料並呈現,但是在『傳統版』上則必須讓 google 可以透過 <網址>?_excaped_fragment_=<書籤> 的方式取得希望被檢索的內文,而 google 則會自動將這兩個內容關聯對應起來,當有人搜尋您網頁中的關鍵字時,不會導到 <網址>?_excaped_fragment_=<書籤> 這個網址中,而是會導入到 <網址>#!<書籤> 的連結中,因此 google 的使用者就可以看到您精心設計互動良好的單頁應用,而不會看到醜醜且互動性較差的傳統版本了。(有關 hashbang 機制的運作原理請參考下列文獻)

Twitter 網站曾經遵照 google 的建議大量地採用了 hashbang 的方式來回應,但是後來卻又因為效能因素而拿掉了 hashbang ,並且建議不要再採用 hashbang 的做法了,您可以在以下幾篇文章中看到這個問題的相關討論與說明。

但是,沒有了 hashbang 機制,那我們的問題又回到了原點 -- 這樣搜尋引擎不就又檢索不到我們的 『單頁應用』了嗎?

還好,HTML5 裡面提出了一個特別的機制,稱為 pushState,可以用來解決這個問題。

奇怪的是, pushState 這個機制和搜尋引擎無關,而是一種操控瀏覽器歷史紀錄 (也就是上一頁,下一頁的那種記錄)的函數,而不是一種解決『單頁應用搜尋問題』的方法。

首先讓我們瞭解一下 pushState 到底是什麼東東!筆者建議各位讀者此時先詳細看看下列文章,因為筆者覺得自己也無法寫得比他好了,所以索性就不寫了。

如果您仔細閱讀完上述文章之後,應該會對 pushState 已經有清楚的理解了。

但是,pushState 如何讓搜尋引擎能夠搜尋到我們的文件呢? 筆者也曾經百思不解阿!

後來,我大概想通了!

其實,上述問題是個錯誤的問法,pushState 當然不是用來解決『單頁應用搜尋問題』的,但是只要伺服器設計得好,那麼搜尋引擎就可以自然地搜尋到那些文件的內容。

這該怎麼說呢?

上文中所謂『伺服器設計得好』,意思是『伺服器』必須要能夠區分『搜尋引擎』和『瀏覽器使用者』,然後分別進行不同的回應。

對於『搜尋引擎』而言,伺服器只要將想要被索引的頁面內容取出並且傳回去就行了,於是伺服器就能正確的索引你的網頁。

但是對於『瀏覽器使用者』(通常是人類)而言,伺服器必須傳回『單頁應用』,然後在互動的過程中讓使用者透過『點選連結,按鈕或填表單』的方式,得到對應的網頁呈現結果,而這也正是單頁應用所希望達成的目標。

在『單頁應用』的互動的過程中,該『單頁』可以透過 pushState 讓網址的顯示就像一般的網頁一樣,如此當使用者進行剪貼分享,或者是按上下頁的時候,都會得到正常的畫面。

於是 google 可以正確地搜尋到網頁,而使用者分享到臉書中的也是正確的網址和標題,因此就相當完美的解決了原本 google 的 hashbang 機制所想要解決的問題。

所以我們只能說, hashbang 與 pushState 兩種不同的機制, 從完全不同的觀點出發,但是最後卻解掉了同一個問題。

Google 從搜尋引擎的立場出發,企圖解決『單頁應用』的搜尋問題,於是發展出了 hashbang 技術,但是該技術最後卻慘遭淘汰!

而 pushState 則從瀏覽器規格的角度出發,結果不但解決了連結分享的問題,也同時解決了『單頁應用的搜尋問題』,只是不知道這個過程到底是一種意外或者是人為智慧的高超設計呢?

這種情況在科技發展史上似乎是很常見的,美妙的解法往往來自完全不同的領域,而唯一會阻礙你的,就只是想像力而已!


本文部份內容與大部份圖片修改自 維基百科 , 使用時請遵守 姓名標示、相同方式分享 授權。
編輯: 陳鍾誠 email: ccckmit@gmail.com