緩存方案

什麼是Web緩存

Web緩存是指一個Web資源(如html頁面,圖片,js,數據等)存在於Web服務器和客戶端(瀏覽器)之間的副本。緩存會根據進來的請求保存輸出內容的副本;當下一個請求來到的時候,若是是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,仍是向源服務器再次發送請求。比較常見的就是瀏覽器會緩存訪問過網站的網頁,當再次訪問這個URL地址的時候,若是網頁沒有更新,就不會再次下載網頁,而是直接使用本地緩存的網頁。只有當網站明確標識資源已經更新,瀏覽器纔會再次下載網頁。至於瀏覽器和網站服務器是如何標識網站頁面是否更新的機制,將在後面介紹。javascript

 

Web緩存的做用

使用Web緩存的做用實際上是很是顯而易見的:php

減小網絡帶寬消耗

不管對於網站運營者或者用戶,帶寬都表明着金錢,過多的帶寬消耗,只會便宜了網絡運營商。當Web緩存副本被使用時,只會產生極小的網絡流量,能夠有效的下降運營成本。css

下降服務器壓力

給網絡資源設定有效期以後,用戶能夠重複使用本地的緩存,減小對源服務器的請求,間接下降服務器的壓力。同時,搜索引擎的爬蟲機器人也能根據過時機制下降爬取的頻率,也能有效下降服務器的壓力。html

減小網絡延遲,加快頁面打開速度

帶寬對於我的網站運營者來講是十分重要,而對於大型的互聯網公司來講,可能有時由於錢多而真的不在意。那Web緩存還有做用嗎?答案是確定的,對於最終用戶,緩存的使用可以明顯加快頁面打開速度,達到更好的體驗。前端

 

Web緩存的類型

在Web應用領域,Web緩存大體能夠分爲如下幾種類型:html5

數據庫數據緩存

Web應用,特別是SNS類型的應用,每每關係比較複雜,數據庫表繁多,若是頻繁進行數據庫查詢,很容易致使數據庫不堪重荷。爲了提供查詢的性能,會將查詢後的數據放到內存中進行緩存,下次查詢時,直接從內存緩存直接返回,提供響應效率。好比經常使用的緩存方案有memcached等。  java

服務器端緩存

 代理服務器緩存mysql

代理服務器是瀏覽器和源服務器之間的中間服務器,瀏覽器先向這個中間服務器發起Web請求,通過處理後(好比權限驗證,緩存匹配等),再將請求轉發到源服務器。代理服務器緩存的運做原理跟瀏覽器的運做原理差很少,只是規模更大。能夠把它理解爲一個共享緩存,不僅爲一個用戶服務,通常爲大量用戶提供服務,所以在減小相應時間和帶寬使用方面頗有效,同一個副本會被重用屢次。常見代理服務器緩存解決方案有Squid等,這裏再也不詳述。ios

 CDN緩存c++

CDN(Content delivery networks)緩存,也叫網關緩存、反向代理緩存。CDN緩存通常是由網站管理員本身部署,爲了讓他們的網站更容易擴展並得到更好的性能。瀏覽器先向CDN網關發起Web請求,網關服務器後面對應着一臺或多臺負載均衡源服務器,會根據它們的負載請求,動態將請求轉發到合適的源服務器上。雖然這種架構負載均衡源服務器之間的緩存無法共享,但卻擁有更好的處擴展性。從瀏覽器角度來看,整個CDN就是一個源服務器,從這個層面來講,本文討論瀏覽器和服務器之間的緩存機制,在這種架構下一樣適用。

 

瀏覽器端緩存

瀏覽器緩存根據一套與服務器約定的規則進行工做,在同一個會話過程當中會檢查一次並肯定緩存的副本足夠新。若是你瀏覽過程當中,好比前進或後退,訪問到同一個圖片,這些圖片能夠從瀏覽器緩存中調出而即時顯現。

 

Web應用層緩存

應用層緩存指的是從代碼層面上,經過代碼邏輯和緩存策略,實現對數據,頁面,圖片等資源的緩存,能夠根據實際狀況選擇將數據存在文件系統或者內存中,減小數據庫查詢或者讀寫瓶頸,提升響應效率。

 

 

 

 

Web瀏覽器的緩存機制 

 

Web緩存的工做原理

 

全部的緩存都是基於一套規則來幫助他們決定何時使用緩存中的副本提供服務(假設有副本可用的狀況下,未被銷燬回收或者未被刪除修改)。這些規則有的在協議中有定義(如HTTP協議1.0和1.1),有的則是由緩存的管理員設置(如DBA、瀏覽器的用戶、代理服務器管理員或者應用開發者)。

瀏覽器端的緩存規則

對於瀏覽器端的緩存來說,這些規則是在HTTP協議頭和HTML頁面的Meta標籤中定義的。他們分別從新鮮度校驗值兩個維度來規定瀏覽器是否能夠直接使用緩存中的副本,仍是須要去源服務器獲取更新的版本。

新鮮度(過時機制):也就是緩存副本有效期。一個緩存副本必須知足如下條件,瀏覽器會認爲它是有效的,足夠新的:

  1. 含有完整的過時時間控制頭信息(HTTP協議報頭),而且仍在有效期內;
  2. 瀏覽器已經使用過這個緩存副本,而且在一個會話中已經檢查過新鮮度;

知足以上兩個狀況的一種,瀏覽器會直接從緩存中獲取副本並渲染。

校驗值(驗證機制):服務器返回資源的時候有時在控制頭信息帶上這個資源的實體標籤Etag(Entity Tag),它能夠用來做爲瀏覽器再次請求過程的校驗標識。如過發現校驗標識不匹配,說明資源已經被修改或過時,瀏覽器需求從新獲取資源內容。

瀏覽器緩存的控制

使用HTML Meta 標籤

Web開發者能夠在HTML頁面的<head>節點中加入<meta>標籤,代碼以下:

1

<META HTTP-EQUIV="Pragma" CONTENT="no-cache">

上述代碼的做用是告訴瀏覽器當前頁面不被緩存,每次訪問都須要去服務器拉取。使用上很簡單,但只有部分瀏覽器能夠支持,並且全部緩存代理服務器都不支持,由於代理不解析HTML內容自己。

能夠經過這個頁面測試你的瀏覽器是否支持:Pragma No-Cache Test 。

使用緩存有關的HTTP消息報頭

一個URI的完整HTTP協議交互過程是由HTTP請求和HTTP響應組成的。有關HTTP詳細內容可參考《Hypertext Transfer Protocol — HTTP/1.1》、《HTTP協議詳解》等。

在HTTP請求和響應的消息報頭中,常見的與緩存有關的消息報頭有:

HTTP緩存相關報頭

 

Cache-Control與Expires

Cache-Control與Expires的做用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據仍是從新發請求到服務器取數據。只不過Cache-Control的選擇更多,設置更細緻,若是同時設置的話,其優先級高於Expires

Last-Modified/ETag與Cache-Control/Expires

配置Last-Modified/ETag的狀況下,瀏覽器再次訪問統一URI的資源,仍是會發送請求到服務器詢問文件是否已經修改,若是沒有,服務器會只發送一個304回給瀏覽器,告訴瀏覽器直接從本身本地的緩存取數據;若是修改過那就整個數據從新發給瀏覽器;

Cache-Control/Expires則不一樣,若是檢測到本地的緩存仍是有效的時間範圍內,瀏覽器直接使用本地副本,不會發送任何請求。二者一塊兒使用時,Cache-Control/Expires的優先級要高於Last-Modified/ETag。即當本地副本根據Cache-Control/Expires發現還在有效期內時,則不會再次發送請求去服務器詢問修改時間(Last-Modified)或實體標識(Etag)了。

通常狀況下,使用Cache-Control/Expires會配合Last-Modified/ETag一塊兒使用,由於即便服務器設置緩存時間, 當用戶點擊「刷新」按鈕時,瀏覽器會忽略緩存繼續向服務器發送請求,這時Last-Modified/ETag將可以很好利用304,從而減小響應開銷。

Last-Modified與ETag

你可能會以爲使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,爲何還須要Etag(實體標識)呢?HTTP1.1中Etag的出現主要是爲了解決幾個Last-Modified比較難解決的問題:

  1. Last-Modified標註的最後修改只能精確到秒級,若是某些文件在1秒鐘之內,被修改屢次的話,它將不能準確標註文件的新鮮度
  2. 若是某些文件會被按期生成,當有時內容並無任何變化,但Last-Modified卻改變了,致使文件無法使用緩存
  3. 有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形

Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的惟一標識符,可以更加準確的控制緩存。Last-Modified與ETag是能夠一塊兒使用的,服務器會優先驗證ETag,一致的狀況下,纔會繼續比對Last-Modified,最後才決定是否返回304。Etag的服務器生成規則和強弱Etag的相關內容能夠參考,《互動百科-Etag》和《HTTP Header definition》,這裏再也不深刻。

用戶操做行爲與緩存

用戶在使用瀏覽器的時候,會有各類操做,好比輸入地址後回車,按F5刷新等,這些行爲會對緩存有什麼影響呢?

用戶操做與緩存

經過上表咱們能夠看到,當用戶在按F5進行刷新的時候,會忽略Expires/Cache-Control的設置,會再次發送請求去服務器請求,而Last-Modified/Etag仍是有效的,服務器會根據狀況判斷返回304仍是200;而當用戶使用Ctrl+F5進行強制刷新的時候,只是全部的緩存機制都將失效,從新從服務器拉去資源。

相關有趣的分享:

瀏覽器緩存機制》:不一樣瀏覽器對用戶操做行爲處理比較

HTTP 304客戶端緩存優化的神奇做用和用法》:強行在代碼層面比對文件的Last-Modified時間,保證用戶使用Ctrl+F5進行刷新的時候也能正常返回304

 

哪些請求不能被緩存?

沒法被瀏覽器緩存的請求:

  1. HTTP信息頭中包含Cache-Control:no-cache,pragma:no-cache,或Cache-Control:max-age=0等告訴瀏覽器不用緩存的請求
  2. 須要根據Cookie,認證信息等決定輸入內容的動態請求是不能被緩存的
  3. 通過HTTPS安全加密的請求(有人也通過測試發現,ie其實在頭部加入Cache-Control:max-age信息,firefox在頭部加入Cache-Control:Public以後,可以對HTTPS的資源進行緩存,參考《HTTPS的七個誤解》)
  4. POST請求沒法被緩存
  5. HTTP響應頭中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的請求沒法被緩存

 

 

 

如何構建可緩存站點

 

前面瞭解了Web緩存的運行機制極其重要性以後,咱們能夠從如下這些方面去努力改善咱們的站點,保證緩存被最有效的利用,達到最佳的性能。

同一個資源保證URL的穩定性

URL是瀏覽器緩存機制的基礎,因此若是一個資源須要在多個地方被引用,儘可能保證URL是固定的。同時,比較推薦使用公共類庫,好比Google Ajax Library等,有利於最大限度使用緩存

給Css、js、圖片等資源增長HTTP緩存頭,並強制入口Html不被緩存

對於不常常修改的靜態資源,好比Css,js,圖片等,能夠設置一個較長的過時的時間,或者至少加上Last-Modified/Etag,而對於html頁面這種入口文件,不建議設置緩存。這樣既能保證在靜態資源不變了狀況下,能夠不重發請求或直接經過304避免重複下載,又能保證在資源有更新的,只要經過給資源增長時間戳或者更換路徑,就能讓用戶訪問最新的資源

減小對Cookie的依賴

過多的使用Cookie會大大增長HTTP請求的負擔,每次GET或POST請求,都會把Cookie都帶上,增長網絡傳輸流量,致使增加交互時間;同時Cache是很難被緩存的,應該儘可能少使用,或者這在動態頁面上使用。

減小對HTTPS加密協議的使用

經過HTTPS請求的資源,默認是不會被緩存的,必須經過特殊的配置,才能讓資源獲得緩存。建議只對涉及敏感信息的請求使用HTTPS傳輸,其餘相似Css,Js,圖片這些靜態資源,儘可能避免使用。

多用Get方式請求動態Cgi

雖然POST的請求方式比Get更安全,能夠避免相似密碼這種敏感信息在網絡傳輸,被代理或其餘人截獲,可是Get請求方式更快,效率更高,並且能被緩存,建議對於那些不涉及敏感信息提交的請求儘可能使用Get方式請求

動態CGI也是能夠被緩存

若是動態腳本或CGI輸入的內容在必定的時間範圍內是固定的,或者根據GET參數相同,輸入的內容相同,咱們也認爲請求是能夠被緩存的,有如下幾種方式,能夠達到這個效果:

  1. 讓動態腳本按期將內容改變時導出成靜態文件,Web直接訪問帶有Last-Modified/Etag的靜態文件
  2. 開發者能夠經過代碼給動態腳本的響應頭中添加Cache-Control: max-age,告訴瀏覽器在過時前能夠直接使用副本
  3. 經過代碼給動態腳本的響應頭添加Last-Modified/Etag信息,瀏覽器再次請求的時候,能夠經過解析If-Modified-Since/If-None-Match得知瀏覽器是否存在緩存,由代碼邏輯控制是否返回304

 

如何給站點增長緩存機制

HTTP請求/響應頭中緩存報頭對有效利用站點緩存,做爲一個Web前端開發者,我要作什麼呢?答案是:啥都不用作。不過要去推進Web運營人員、Web後端開發人員分別給服務器和動態腳本CGI增長合適的緩存報頭。

服務器配置

Apache相關配置參考:mod_headersmod_headers

編寫可緩存的動態腳本

服務器配置的方法比較簡單通用,可是若是遇到沒有權限修改服務器配置或者須要添加更細緻的Expires/Cache-Control/Etag等信息時,不妨能夠試試從代碼層面去添加這些信息。不一樣語言寫法實現略有不一樣,但思路都是一致的。能夠在單獨開闢一個獨立模塊,調用語言庫提供的添加報頭的接口,根據須要設置報頭信息。當某個請求的動態腳本須要被緩存時,能夠採用相似include,require等模塊引用方式調用公共模塊,實現緩存機制。

Php實現代碼實例以下:

Cache.php

<?php
Header(「Cache-Control: must-revalidate」);

$offset = 60 * 60 * 24 * 3;
$ExpStr = 「Expires: 」 . gmdate(「D, d M Y H:i:s」, time() + $offset) . 」 GMT」;
Header($ExpStr);
?>

<?php

Require(Cache.php)

// business code here

// todo

?>

 

 

 

HTML5時代的Web緩存機制

 

隨着現代瀏覽器的推進,Flash放棄對移動端的支持,HTML5無疑成爲當前Web前端煊赫一時的話題。各大遊戲開發商、App開發商紛紛投入人力進行研究和技術儲備。相信不久的未來,HTML5會迎來一個快速發展和普及的春天。那麼,HTML5這個新一代的標準,又給咱們帶來哪些緩存機制呢?

 

 

 HTML5 之離線應用Manifest

咱們知道,使用傳統的技術,就算是對站點的資源都實施了比較好的緩存策略,可是在斷網的狀況下,是沒法訪問的,由於入口的HTML頁面咱們通常運維的考慮,不會對其進行緩存。HTML5的Cache Manifest離線應用特性就可以幫助咱們構建離線也能使用的站點,全部的資源都使用瀏覽器本地緩存,固然前提是要求在聯網的情形下使用過一次站點。

如何實現離線訪問特性

實現的步驟很是簡單,主要3個步驟:

1)在服務器上添加MIME TYPE支,讓服務器可以識別manifest後綴的文件

AddType text/cache-manifest manifest

2)建立一個後綴名爲.manifest的文件,把須要緩存的文件按格式寫在裏面,並用註釋行標註版本

CACHE MANIFEST

# 直接緩存的文件

CACHE:

Path/to/cache.js

# version:2012-03-20

3)給 <html> 標籤加 manifest 屬性,並引用manifest文件

具體能夠參考:HTML5 緩存: cache manifest

<html manifest=」path/to/name-of.manifest」>

離線應用訪問及更新流程

  1. 第一次訪問離線應用的入口頁HTML(引用了manifest文件),正常發送請求,獲取manifest文件並在本地緩存,陸續拉取manifest中的須要緩存的文件
  2. 再次訪問時,沒法在線離線與否,都會直接從緩存中獲取入口頁HTML和其餘緩存的文件進行展現。若是此時在線,瀏覽器會發送請求到服務器請求manifest文件,並與第一次訪問的副本進行比對,若是發現版本不一致,會陸續發送請求從新拉取入口文件HTML和須要緩存的文件並更新本地緩存副本
  3. 以後的訪問重複第2步的行爲

離線機制的緩存用途

從Manifest的機制來看,即便咱們不是爲了建立離線應用,也一樣可使用這種機制用於緩存文件,能夠說是給Web緩存提供多一種能夠選擇的途徑。

存在的問題:緩存文件更新控制不靈活

就目前HTML5提供的manifest機制來說,一個頁面只能引用一個manifest頁面,並且一旦發現這個manifest改變了,就會把裏面全部定義的緩存文件所有從新拉取一遍,無論實際上有沒有更新,控制比較不靈活。針對這個問題,也有的同窗提出了一些建議,好比把須要緩存的文件分模塊切分到不一樣manifest中,並分開用HTML引用,再使用強大的iframe嵌入到入口頁面,這樣就當某一個模式須要有更新,不會致使其餘模塊的文件也從新拉取一遍。

 

HTML5 之本地存儲localstorage

HTML5給咱們提供本地存儲localstorage特性,嚴格來說,其實已經不算傳統Web緩存的範疇。由於它存儲的地方是跟Web緩存分開的,是瀏覽器從新開闢的一個地方。

localstorage的做用

本地存儲localstorage的做用主要使Web頁面可以經過瀏覽器提供的set/get接口,存儲一些自定義的信息到本地硬盤,而且在單次訪問或之後的訪問過程當中隨時獲取或修改。

Localstorage的使用

Localstorage提供了幾個很是易用的Api,setItem/getItem/removeItem/clear,具體的能夠參考:Html5 Step by Step(二) 本地存儲

Localstorage的緩存用途

Localstorage設計的本意多是用來存儲一些用戶操做的個性化設置的文本類型的信息和數據,當咱們其實也可能拿來當Web緩存區使用,好比咱們能夠將Base64格式編碼的圖片信息,存在localstorage中,再次訪問時,直接本地獲取後,使用Css3的Data:image的方式直接展示出來。

存在的問題:大小限制

按照目前標準,目前瀏覽器只給每一個獨立的域名提供5m的存儲空間,當存儲超過5m,瀏覽器就會彈出警告框。

 

能夠說,HTML5的Manifest和localstorage是給咱們在考慮Web緩存的時候提供了多一種思路,當你開發的應用只面對現代瀏覽器的時候,不妨能夠考慮一下。

 

 

Web App時代的緩存機制新思路

 

Web App的概念逐漸被業界承認,各大互聯網公司也紛紛推出Web App開發大賽,積極引入到他們的開放平臺,比較著名相似facebook農場,qzone偷菜之類的。Web開發逐漸從Web Page的進入到Web App的時代,想詳細瞭解的話,能夠看下超叔在D2上分享的分享《開放時代:從Web Page到Web APP》視頻Slide

Web App常見架構

以WebQQ例,WebQQ這個站點的全部內容都是一個頁面裏面呈現的,咱們看到的相似windows操做系統的框架,是它的頂級容器和框架,由AlloyOS的內核負責統籌和管理,而後其餘模塊,好比壁紙設置,消息中心,App Store都是以模塊的形式,並用iframe的方式嵌入到頂級容器中。具觀察,如今愈來愈多的Web應用都傾向於使用這個的架構,這樣作好處是很明顯的,好比頂級框架能夠維持一個不變的javascript上下文便於管理;關閉模塊的iframe後,內存能夠更好的釋放;利用iframe的安全機制最大限度的保證內核的安全和穩定等等。

這種Web的架構,其實也給咱們Web前端提供了從代碼邏輯層面上給Web應用實現緩存提供了可能。

 

緩存Ajax請求

因爲頂級框架頁面是不會因爲調整刷新而致使javascript上下文丟失,因此底層或各個模塊所須要的Ajax請求,都是能夠經過頂級框架統一請求後,並以信息服務的形式對外提供Api調用。對於一些實時性要求不是很強的請求來講,能夠由頂級框架作統一緩存,按期更新。這種作法能夠不影響用戶體驗的前提下,明顯減小請求數,下降網絡流量,並間接減輕了服務器的壓力。

經過Javascript實現內存緩存

跟緩存Ajax請求的結果相似,程序運行過程當中的其餘數據,其實也能夠採用相似的方式在頂級容器的Javascript上下文中緩存。

 

Web App發展新方向:Web-Client模式

隨着Web App的進一步發展,貌似瀏覽器已經沒法阻擋Web應用探索更前端,更本地化Native App的用戶體驗。好比目前的Qplus豆瓣莢等應用,都採用Client、Web相結合的開發模式。這樣作便可以利用Web開發迭代更新快、UI開發成本低等特色,有能夠利用客戶端的能力爲Web實現不少沒法實現的功能。以Qplus爲例,Qplus不但內嵌了Webkit內核,還未Webkit上定製了不少便利的接口,好比跨Web-Client的拖曳、多線程下載等。在這種發展新模式下,Web緩存又能有什麼考慮的發張方向呢?

客戶端提供緩存讀寫能力

咱們知道,HTML5的localstorage僅僅只能支持5m的存儲。咱們能夠按localstorage的設計思路,讓客戶端爲Web定製更大,更靈活的本地存儲功能。到時,Web緩存能作的事情就會更多。

 

以上就當前Web App的發展趨勢,討論了對於Web緩存領域,有哪些能夠作,能夠考慮的方向。固然,這些作法,合不合理,合不合適都仍是值得討論和商榷的,若是你有想法,均可以隨時聯繫並一塊兒討論。

 

全文總結

本文嘗試概述目前Web緩存方向的現狀,以及HTML5和Web App時代下,Web緩存能夠考慮的新方向。因爲時間倉促和表達歸納能力有限,有可能有表達不妥的地方,歡迎指正討論。

 

 

 

進擊的Hybrid App,量身定作緩存機制

 

 

前言

 

前面的文章分別簡述了Web緩存、相關機制、以及 html5 和 Web App 時代咱們能夠選擇的緩存思路。轉眼過了很長時間,這期間移動互聯網成爲你們討論和學習的焦點,部門也有不少同窗陸續接觸 Mobile Native App 和 Mobile Web App 的開發。同時,還有部分同窗專一 QQ 內嵌 Webkit + Client 這種Hybrid App模式的開發,繼續推進 QQ 客戶端 Web 化的進程。

引用張圖,簡單粗俗的解釋下 Native App、Web App 和 Hybrid App

hybrid-app

Navtie App: 使用平臺系統提供的原生語言來編寫的 App,若是Android用java,ios用objective-c,windows c++等

Web App:主要使用 Web 技術js/html/css進行編寫,運行在各平臺系統瀏覽器或瀏覽器組件中

Hybrid App:混合使用前面兩種技術,部分代碼以 Web 技術編寫,部分代碼由某些 Native Container 承擔(如 Phongap 插件,PC/手機 QQ客戶端等)

 

現有的緩存機制及問題

移動互聯網網速慢、QQ 客戶端對 Web 模塊可用性要求高,使得咱們無論作 Mobile Web App 開發、仍是 PC Web App 開發,都必須對 Web 緩存有更深刻的理解和利用。PC QQ 和 手機 QQ 都有基本 Webkit 的 Webview,除了傳統常規提到的緩存外,參閱《Web瀏覽器的緩存機制 》,咱們最早想到的優化方案就是前面文章提到的 Html5 App Cache,Web Storage,詳細請參閱《HTML5時代的Web緩存機制》 和《Web App時代的緩存機制新思路》。

但,使用的過程當中,咱們發現了一些關於 html5 app cache 的問題:

一、第一次必須聯網,在移動網絡下首次打開效果很是不理想

二、http 頭設置會致使 manifest 沒法正常更新,見 http://www.alloyteam.com/2012/01/html5-offline-app-update-problem/

三、Manifest 中緩存文件一旦下載出錯,後續的文件將再也不下載,拋出錯誤事件,見:http://stackoverflow.com/questions/6666513/html5-manifest-caching-error

四、Android 系統版本衆多,較低版本的瀏覽器對 manifest 支持不完善

五、引用 manifest 的 html 頁面自己也會被緩存

六、《慎用manifest》一文提到的如:頁面的參數傳遞、manifest 的發佈、回滾、下線等問題

從上面能夠看出,html5 雖然提供基於 manifest 這種離線緩存的機制,但在實際運用過程當中仍是會遇到很是多的問題,因而,咱們開始思考,既然是 hybrid app,與其花大量時間踩坑,有資源有條件,不如更激進一點,嘗試利用客戶端能力來量身定作一套本身適用的緩存機制。因而 Alloykit 誕生了。

 

關於 Alloykit

Alloykit 是 PC/手機 QQ 上基於 Webview 開發的一個方便易用的開發組件,可以使基於 Webkit 開發的模塊,快速擁有 Web 資源本地化、Common Api、自動種入登陸態和續期、診斷上報、DNS管理、開發者工具支持、關鍵性能數據上報等特性。

Alloykit 各模塊及主要功能:

本地化模塊:把靜態資源下載到本地,而後經過訪問本地資源代替去服務器請求

Common Api模塊:對經常使用共性的 Client 接口進行封裝,Web能夠內嵌 Commonapi.js 進行方便調用

登陸態管理模塊:web 登陸態自動續期,登陸態拉取失敗走 Pt 跳轉

診斷上報模塊:診斷修復用戶問題(清緩存,DNS,從新加載頁面),截屏並收集用戶本機網絡信息,上報到後臺進行分析。

DNS管理模塊:域名預加載,域名 ip 驗證等

開發模式:開發模式開關,開發者調試工具支持

數據上報:通用控件在不一樣業務中的關鍵上報點

下面主要介紹一下本地化緩存模塊的設計思路,後面有機會再單獨介紹其它的模塊。

 

本地化模塊

用一張圖大體示意以下:

cache2

由上圖能夠看出,本地化模塊主要由下面兩個子模塊組成:

一、攔截器:採用的一種相似 Fiddler AutoResponse 的本地替換思路,經過攔截全部 web 請求,進行本地化資源匹配,命中則用本地資源直接替換,不然,正常發起請求。

二、更新器:根據更新策略進行新版本資源檢測,負責下載和維護本地緩存目錄中的資源,並將更新過程關鍵點經過事件通知到 Web 頁面備用。

原理很簡單,使用也很簡單,主要分爲如下幾個步驟:

一、客戶端開發階段:新建窗口的時候,只須要經過配置文件,將窗口類型聲明爲 AlloykitWindow

二、前端開發階段:開發過程透明,不須要任何特殊處理

三、前端發佈階段:打包靜態資源 zip 包

把業務涉及到而且但願離線的域名和資源打包,假設你的頁面用到了web.qq.com、cdn.qq.com、test.statics.qq.com等域名,以下圖所示,爲每一個域名建一個目錄(若只有一個域名,則只創建一個目錄),而後按照資源的url創建各級子目錄並把資源放到相應的子目錄下。

好比你有這樣一個html頁面:http://web.qq.com/module1/helloworld.html

把須要離線的頁面文件和圖片資源放到目錄web.qq.com/module1下便可,如圖:

pack-zip

使用 zip 壓縮軟件,將全部資源打包爲一個 zip 包。

四、運維發佈階段:

  • 正常發佈線上資源
  • 登陸資源包管理平臺,提交對應 zip 包
  • 須要打包到客戶端安裝包的資源,單獨提交給客戶端開發負責打包

 

Alloykit 本地化 和 H5 manifest 對比

一、Alloykit 能夠選擇將關鍵頁面直接打包到客戶端或App安裝包,首次打開不須要依賴網絡條件

二、對於沒有打包到安裝包的頁面,也能夠經過配置,讓客戶端啓動後提早加載資源包

三、Alloykit 開發過程體驗更簡單,基本透明

四、Alloykit 把全部資源打包爲一個 zip 包進行下載,更高效

五、Alloykit 經過客戶端提供的基於 tcp 的下載通道進行下載,並有重試機制,更加穩定可靠

六、Alloykit 能夠經過自身封裝,支持多平臺,避免開發者兼容多平臺帶來的麻煩

七、Alloykit 能夠經過協議的設計,輕鬆實現刷新緩存、封版、下線離線特性等功能

這個本地化機制目前已有模塊開始試用,在享受量身定製的緩存機制帶來的性能提高和開發便利的同時,咱們開始遇到並思考本地化以後的一些問題。

 

本地化以後

一、本地化文件的安全問題

緩存目錄中本地文件,第三方是有辦法找到並進行強制修改,可能存在不安全的因素。有同窗可能會說這個擔憂其實畫蛇添足,好比 Chrome Cache 文件寫入磁盤的算法是開源的,若是第三方(相似 ChromeCacheView)軟件實現了這個算法,就能對緩存文件進行修改,也存在相似安全問題。話雖如此,但是仍是要作最壞的打算,說不定哪天數字搞你一下。要設計一種機制作保障。這種提供兩種思路:

1)設計一種相似 Chrome Cache 閉源算法,把獲取的資源包以這種算法讀寫入本地磁盤上。

2)使用非對稱加密算法

客戶端開發的時候,內嵌私鑰

資源包 zip 中加入一個包含全部文件 md5 信息的json文件,並使用對應的公鑰進行加密

客戶端獲取 zip 包後,使用私鑰對 json 文件解密,獲取 md5 信息,逐個進行校驗

 

二、Web 項目運營思路轉變

Web 項目一旦使用了本地化特性,無論是 H5 的 manifest 仍是 Alloykit ,都會存在滯後一次更新,因此始終都會存在舊版本的長尾問題。因此這類型的項目給運營提出了更高的要求:

1)後臺 CGI 接口,儘可能考慮向前兼容,保證協議結構不變,若是確實須要改動,建議啓用新路徑

2)前端資源文件,建議採用增量的形式發佈,好比 main.js ,發佈的時候建議編譯成 main-****.js(通常使用時間戳或md5後8位)

這樣作的好處很明顯,能夠最大限度避免發佈引發的波動,同時也能夠支持 web 項目多版本並存,避免多版本相互影響。使用 grunt 或 modjs 能夠輕鬆完成這個自動化構建編譯工做。

3)Web 版本的鋪量速度有所降低,因此對版本質量的要求更高,不建議太頻繁、未經嚴格測試的版本發佈

可見是否使用本地化,也須要作慎重的考慮,在性能和各個方面作權衡。

 

三、本地化以後的可用性問題

Alloykit 本地化以後,理論上在斷網的狀況下,頁面也是打開的。可是要保證頁面可用,其實還有很長的路要走。

針對那種單機的 h5 遊戲或者簡單頁面,其實無需任何處理就能保證離線的訪問效果。但,目前徹底單機的 Web App 基本是不存在,大量的動態的數據和社會化的交互。若是本地化以後不作任何處理,那麼在離線的狀況下,基本也是隻有頁面框架,大量的頁面空白和 ajax 請求超時,基本也至關於不可用。那麼,花了這麼大力氣定製的本地化機制就僅僅保證打開的時候可看不可用嗎?有什麼辦法能夠改善嗎?

答案是有的,這時 Web Storage 和 Web Database 就能夠派上用場了,詳細使用能夠 Google 或者參考索引中的第四、5篇文章。

一些典型的離線場景及處理方案:

1)離線寫操做:將 Ajax 請求以及相關參數保存到 localStorage 隊列中,網絡上線後,觸發執行隊列中的操做

2)離線讀操做:頁面上有須要經過 Ajax 獲取動態的數據或遠程圖片進行渲染的塊,能夠經過前端 hardcode 一些默認數據,而且將最近一次 ajax 結果存儲到 localStorage 中,圖片能夠轉爲 base64 字符串才用一樣的方式處理

localStorage 有同源限制,大小也有限制,而且只能存儲字符串,須要存儲圖片須要進行轉化,比較繁瑣耗性能。能否跟激進一些,由客戶端提供模擬 localStorage,自行開闢存儲空間,提供接口進行存取和校驗?徹底是可行的,而且如今在一些 Mobile 的項目中進行了相關嘗試,接口整合到 CommonApi 模塊中。

 

總結

獨立於標準以外重複製造輪子,自己不是太推薦的作法。在目前標準和平臺支持未完善,以及在特定場景下有欠缺的情形下,資源容許,咱們選擇了嘗試新方法,針對Hybrid App 這種特殊的運用場景定製了一種本地化緩存和存儲的實現方案。時間倉促,方案自己仍處於測試階段,某些方面考慮不免會有欠考慮,很是歡迎同窗們留言指出、改進。

相關文章
相關標籤/搜索