連不上網?英國衛報的個性離線頁面是這樣做的
我們是如何使用serviceworker來為theguardian.com構建一個自定義的離線頁面。...
我們是如何使用 service worker 來為 theguardian.com 構建一個自定義的離線頁面。
theguardian.com 的離線頁面。插圖:oliver Ash
你正在通往公司路上的地鐵里,在手機上打開了 Guardian 應用。地鐵被隧道包圍著,不過這個應用可以如常運行,即使沒有網絡連接,你也能獲得完整的功能,除了顯示的內容可能有點舊。如果你嘗試在網站上也這么干,可惜它完全沒法加載:
安卓版 Chrome 的離線頁面
Chrome 在離線頁面上有個隱藏的游戲(桌面版上按空格鍵,手機版上點擊那只恐龍),這多少能減輕一點你的煩躁。不過我們可以做得更好。
Service workers 允許網站作者攔截自己站點的所有網絡請求,這也就意味著我們可以提供完善的離線體驗,就像原生應用一樣。在 Guardian 網站,我們最近上線了一個自定義的離線體驗功能。當用戶離線的時候,他們會看到一個帶有 Guardian 標識的頁面,上面帶有一個簡短的離線提示,還有一個填字游戲,他們可以在等待網絡連接的時候玩玩這個找點樂子。這篇博客解釋了我們是如何構建它的,不過在開始之前,你可以先自己試試看。
試試看
你需要一個支持 Service Worker 和 fetch API 的瀏覽器。截止到本文編寫時只有 Chrome(手機版和桌面版)同時支持這兩種 API(譯者注:Opera 目前也支持這兩者),不過 Firefox 很快就要支持了(在每日更新的版本中已經支持了),除了 Safari 之外的所有瀏覽器也都在躍躍欲試。此外,service worker 只能注冊在使用了 HTTPS 的網站上,theguardian.com 已經開始逐步遷移到 HTTPS,所以我們只能在網站的 HTTPS 部分提供離線體驗。就目前來說,我們選擇了開發者博客作為我們用來測試的地方。所以如果你是在我們網站的 開發者博客 部分閱讀這篇文章的話,很走運。
當你使用支持的瀏覽器訪問我們的開發者博客中的頁面的時候,一切就準備妥當了。斷開你的網絡連接,然后刷新一下頁面。如果你自己沒條件嘗試的話,可以看一下這段演示視頻(譯者注:需翻墻)。
工作原理
通過一段簡單的 Javascript,我們可以指示瀏覽器在用戶訪問頁面的時候立即注冊我們自己的 service worker。目前支持 service worker 的瀏覽器很少,所以為了避免錯誤,我們需要使用特性檢測。
if(navigator.serviceWorker){navigator.serviceWorker.register('/service-worker.js');}
Service worker 安裝事件的一部分,我們可以使用新的緩存 API來緩存我們網站中的各種內容,比如 HTML、CSS 和 JavaScript:
varstaticCacheName='static';varversion=1;functionupdateCache(){returncaches.open(staticCacheName+version).then(function(cache){returncache.addAll(['/offline-page.html','/assets/css/main.css','/assets/js/main.js']);});};self.addEventListener('install',function(event){event.waitUntil(updateCache());});
當安裝完成后,service worker 可以監聽和控制 fetch 事件,讓我們可以完全控制之后網站中產生的所有網絡請求。
self.addEventListener('fetch',function(event){event.respondWith(fetch(event.request));});
在這里我們有很靈活的空間可以發揮,比如下面這個點子,可以通過代碼來生成我們自己的請求響應:
self.addEventListener('fetch',function(event){varresponse=newResponse('<h1>Hello, World!</h1>',{headers:{'Content-Type':'text/html'}});event.respondWith(response);});
還有這個,如果在緩存中找到了請求相應的緩存,我們可以直接從緩存中返回它,如果沒找到的話,再通過網絡獲取響應內容:
self.addEventListener('fetch',function(event){event.respondWith(caches.match(event.request).then(function(response){returnresponse||fetch(event.request);}));});
那么我們如何使用這些功能來提供離線體驗呢?
首先,在 service worker 安裝過程中,我們需要把離線頁面需要的 HTML 和資源文件通過 service worker 緩存下來。在緩存中,我們加載了自己開發的填字游戲的 React應用頁面。之后,我們會攔截所有訪問 theguardian.com 網絡請求,包括網頁、以及頁面中的資源文件。處理這些請求的邏輯大致如下:
- 當我們檢測到傳入請求是指向我們的 HTML 頁面時,我們總是會想要提供最新的內容,所以我們會嘗試把這個請求通過網絡發送給服務器。
- 當我們從服務器得到了響應,就可以直接返回這個響應。
- 如果網絡請求拋出了異常(比如因為用戶掉線了),我們捕獲這個異常,然后使用緩存的離線 HTML 頁面作為響應內容。
- 否則,當我們檢測到請求的不是 HTML 的話,我們會從緩存中查找響應的請求內容。
- 如果找到了緩存內容,我們可以直接返回緩存的內容。
- 否則,我們會嘗試把這個請求通過網絡發送給服務器。
在代碼中,我們使用了新的緩存 API(它是 Service Worker API 的一部分)以及 fetch 功能(用于生成網絡請求),如下所示:
vardoesRequestAcceptHtml=function(request){returnrequest.headers.get('Accept').split(',').some(function(type){returntype==='text/html';});};self.addEventListener('fetch',function(event){varrequest=event.request;if(doesRequestAcceptHtml(request)){// HTML pages fallback to offline pageevent.respondWith(fetch(request).catch(function(){returncaches.match('/offline-page.html');}));}else{// Default fetch behaviour// Cache first for all other requestsevent.respondWith(caches.match(request).then(function(response){returnresponse||fetch(request);}));}});
就只需要這么多!theguardian.com 上的所有代碼都是在 GitHub 上開源的,所以你可以去那兒查看我們的 service worker 的完整版本,或者直接從生產環境上訪問 https://www.theguardian.com/service-worker.js。
我們有充足的理由為這些新的瀏覽器技術歡呼喝彩,因為它可以用來讓你的網站像今天的原生應用一樣,擁有完善的離線體驗。未來當 theguardian.com 完全遷移到 HTTPS 之后,離線頁面的重要性會明顯增加,我們可以提供更加完善的離線體驗。設想一下你在上下班路上網絡很差的時候訪問 theguardian.com,你會看到專門為你訂制的個性化內容,它們是在你之前訪問網站時由瀏覽器緩存下來的。它在安裝過程中也不會產生任何不便,你所需要的只是訪問這個網站而已,不像原生應用,還需要用戶有一個應用商店的賬號才能安裝。Service worker 同樣可以幫助我們提升網站的加載速度,因為網站的框架能夠被可靠地緩存下來,就像原生應用一樣。
如果你對 service worker 很感興趣,想要了解更多內容的話,開發者 Matt Gaunt(Chrome的忠實支持者)寫了一篇更加詳細地介紹 Service Worker 的文章。
-
無相關信息