連不上網(wǎng)?英國衛(wèi)報(bào)的個(gè)性離線頁面是這樣做的

2015-11-27 14:10:00 來源:JobBole.com 作者:佚名 人氣: 次閱讀 176 條評論

我們是如何使用serviceworker來為theguardian.com構(gòu)建一個(gè)自定義的離線頁面。...

我們是如何使用 service worker 來為 theguardian.com 構(gòu)建一個(gè)自定義的離線頁面。

離線網(wǎng)頁 離線網(wǎng)頁程序 網(wǎng)站優(yōu)化 網(wǎng)站策劃

theguardian.com 的離線頁面。插圖:oliver Ash

你正在通往公司路上的地鐵里,在手機(jī)上打開了 Guardian 應(yīng)用。地鐵被隧道包圍著,不過這個(gè)應(yīng)用可以如常運(yùn)行,即使沒有網(wǎng)絡(luò)連接,你也能獲得完整的功能,除了顯示的內(nèi)容可能有點(diǎn)舊。如果你嘗試在網(wǎng)站上也這么干,可惜它完全沒法加載:

離線網(wǎng)頁 離線網(wǎng)頁程序 網(wǎng)站優(yōu)化 網(wǎng)站策劃

安卓版 Chrome 的離線頁面

Chrome 在離線頁面上有個(gè)隱藏的游戲(桌面版上按空格鍵,手機(jī)版上點(diǎn)擊那只恐龍),這多少能減輕一點(diǎn)你的煩躁。不過我們可以做得更好。

Service workers 允許網(wǎng)站作者攔截自己站點(diǎn)的所有網(wǎng)絡(luò)請求,這也就意味著我們可以提供完善的離線體驗(yàn),就像原生應(yīng)用一樣。在 Guardian 網(wǎng)站,我們最近上線了一個(gè)自定義的離線體驗(yàn)功能。當(dāng)用戶離線的時(shí)候,他們會看到一個(gè)帶有 Guardian 標(biāo)識的頁面,上面帶有一個(gè)簡短的離線提示,還有一個(gè)填字游戲,他們可以在等待網(wǎng)絡(luò)連接的時(shí)候玩玩這個(gè)找點(diǎn)樂子。這篇博客解釋了我們是如何構(gòu)建它的,不過在開始之前,你可以先自己試試看。

試試看

你需要一個(gè)支持 Service Worker 和 fetch API 的瀏覽器。截止到本文編寫時(shí)只有 Chrome(手機(jī)版和桌面版)同時(shí)支持這兩種 API(譯者注:Opera 目前也支持這兩者),不過 Firefox 很快就要支持了(在每日更新的版本中已經(jīng)支持了),除了 Safari 之外的所有瀏覽器也都在躍躍欲試。此外,service worker 只能注冊在使用了 HTTPS 的網(wǎng)站上,theguardian.com 已經(jīng)開始逐步遷移到 HTTPS,所以我們只能在網(wǎng)站的 HTTPS 部分提供離線體驗(yàn)。就目前來說,我們選擇了開發(fā)者博客作為我們用來測試的地方。所以如果你是在我們網(wǎng)站的 開發(fā)者博客 部分閱讀這篇文章的話,很走運(yùn)。

當(dāng)你使用支持的瀏覽器訪問我們的開發(fā)者博客中的頁面的時(shí)候,一切就準(zhǔn)備妥當(dāng)了。斷開你的網(wǎng)絡(luò)連接,然后刷新一下頁面。如果你自己沒條件嘗試的話,可以看一下這段演示視頻(譯者注:需翻墻)。

工作原理

通過一段簡單的 Javascript,我們可以指示瀏覽器在用戶訪問頁面的時(shí)候立即注冊我們自己的 service worker。目前支持 service worker 的瀏覽器很少,所以為了避免錯(cuò)誤,我們需要使用特性檢測。

if(navigator.serviceWorker){navigator.serviceWorker.register('/service-worker.js');}

Service worker 安裝事件的一部分,我們可以使用新的緩存 API來緩存我們網(wǎng)站中的各種內(nèi)容,比如 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());});

當(dāng)安裝完成后,service worker 可以監(jiān)聽和控制 fetch 事件,讓我們可以完全控制之后網(wǎng)站中產(chǎn)生的所有網(wǎng)絡(luò)請求。

self.addEventListener('fetch',function(event){event.respondWith(fetch(event.request));});

在這里我們有很靈活的空間可以發(fā)揮,比如下面這個(gè)點(diǎn)子,可以通過代碼來生成我們自己的請求響應(yīng):

self.addEventListener('fetch',function(event){varresponse=newResponse('<h1>Hello, World!</h1>',{headers:{'Content-Type':'text/html'}});event.respondWith(response);});

還有這個(gè),如果在緩存中找到了請求相應(yīng)的緩存,我們可以直接從緩存中返回它,如果沒找到的話,再通過網(wǎng)絡(luò)獲取響應(yīng)內(nèi)容:

self.addEventListener('fetch',function(event){event.respondWith(caches.match(event.request).then(function(response){returnresponse||fetch(event.request);}));});

那么我們?nèi)绾问褂眠@些功能來提供離線體驗(yàn)?zāi)兀?/p>

首先,在 service worker 安裝過程中,我們需要把離線頁面需要的 HTML 和資源文件通過 service worker 緩存下來。在緩存中,我們加載了自己開發(fā)的填字游戲React應(yīng)用頁面。之后,我們會攔截所有訪問 theguardian.com 網(wǎng)絡(luò)請求,包括網(wǎng)頁、以及頁面中的資源文件。處理這些請求的邏輯大致如下:

  1. 當(dāng)我們檢測到傳入請求是指向我們的 HTML 頁面時(shí),我們總是會想要提供最新的內(nèi)容,所以我們會嘗試把這個(gè)請求通過網(wǎng)絡(luò)發(fā)送給服務(wù)器。
    1. 當(dāng)我們從服務(wù)器得到了響應(yīng),就可以直接返回這個(gè)響應(yīng)。
    2. 如果網(wǎng)絡(luò)請求拋出了異常(比如因?yàn)橛脩舻艟€了),我們捕獲這個(gè)異常,然后使用緩存的離線 HTML 頁面作為響應(yīng)內(nèi)容。
  2. 否則,當(dāng)我們檢測到請求的不是 HTML 的話,我們會從緩存中查找響應(yīng)的請求內(nèi)容。
    1. 如果找到了緩存內(nèi)容,我們可以直接返回緩存的內(nèi)容。
    2. 否則,我們會嘗試把這個(gè)請求通過網(wǎng)絡(luò)發(fā)送給服務(wù)器。

在代碼中,我們使用了新的緩存 API(它是 Service Worker API 的一部分)以及 fetch 功能(用于生成網(wǎng)絡(luò)請求),如下所示:

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 的完整版本,或者直接從生產(chǎn)環(huán)境上訪問 https://www.theguardian.com/service-worker.js。

我們有充足的理由為這些新的瀏覽器技術(shù)歡呼喝彩,因?yàn)樗梢杂脕碜屇愕木W(wǎng)站像今天的原生應(yīng)用一樣,擁有完善的離線體驗(yàn)。未來當(dāng) theguardian.com 完全遷移到 HTTPS 之后,離線頁面的重要性會明顯增加,我們可以提供更加完善的離線體驗(yàn)。設(shè)想一下你在上下班路上網(wǎng)絡(luò)很差的時(shí)候訪問 theguardian.com,你會看到專門為你訂制的個(gè)性化內(nèi)容,它們是在你之前訪問網(wǎng)站時(shí)由瀏覽器緩存下來的。它在安裝過程中也不會產(chǎn)生任何不便,你所需要的只是訪問這個(gè)網(wǎng)站而已,不像原生應(yīng)用,還需要用戶有一個(gè)應(yīng)用商店的賬號才能安裝。Service worker 同樣可以幫助我們提升網(wǎng)站的加載速度,因?yàn)榫W(wǎng)站的框架能夠被可靠地緩存下來,就像原生應(yīng)用一樣。

如果你對 service worker 很感興趣,想要了解更多內(nèi)容的話,開發(fā)者 Matt Gaunt(Chrome的忠實(shí)支持者)寫了一篇更加詳細(xì)地介紹 Service Worker 的文章。

    無相關(guān)信息