標籤:

如何利用Webp和http緩存節省30%的網路流量

如何利用Webp和http緩存節省30%的網路流量

來自專欄猿論13 人贊了文章

Webp推出那年,我剛剛考上高中。轉眼間,大學畢業將近一年,我依舊是那個青蔥少年!就像Webp一樣,還是那麼年輕,時至今日尚未嶄露頭角,原因是各大瀏覽器對它的兼容依舊不是那麼的友好。IE爸爸甚至至今都沒有要支持它的跡象。

webp

> 維基百科:WebP最初在2010年發布,目標是減少文件大小,但達到和JPEG格式相同的圖片品質,希望能夠減少圖片檔在網路上的發送時間。 2011年11月8日,Google開始讓WebP支持無損壓縮和透明色(alpha通道)的功能,而在2012年8月16日的引用實做libwebp 0.2.0中正式支持。根據Google較早的測試,WebP的無損壓縮比網路上找到的PNG檔少了45%的文件大小,即使這些PNG檔在使用pngcrush和PNGOUT處理過,WebP還是可以減少28%的文件大小。

簡單來說,Webp格式是一種圖片格式,它有更優秀的圖片壓縮演算法,並且能實現肉眼難以辨識的質量差異,同時它還支持有損無損兩種壓縮模式。

由於是谷歌的親兒子,所以安卓原生瀏覽器對Webp的支持還是比較樂觀的,Chrome桌面版和安卓版的支持也都比較好。國內的瀏覽器也不同程度的對Webp做了很多支持。我去Can I Use上截了張圖過來:

由此可見,市面上佔有率比較大的瀏覽器對Webp的支持還是很不錯的,所以有必要使用起來。其實是之前無意間發現某寶和某東在使用,所以也想在這塊做一些優化。

有圖有真相,先看看優化後的效果吧。

使用前:

使用後:

可以很明顯的看到,僅僅這八張並不是特別大的圖片,便節省了59.3K的流量。下載時間也有明顯的縮短。如果你的web項目是類似於某寶某東那樣有著大量圖片,那麼這塊節省的流量可想而知!

市面上有一些圖片格式轉換工具,我這裡就不一一列舉了。這裡要講的可能是比較簡單的一種使用方式,因為我們的圖片等資源文件託管在阿里雲oss上,它只需要你在請求url裡面帶個參數,就會自動返回你想要的圖片格式。各位看官,如果你們的情況和我不一樣,可能需要自己對圖片做一部分處理或者別的雲存儲也有類似的解決方案。

好的,言歸正傳,接下來說說我的解決方案。我們的Web是利用Vue實現的前後端同構的,所以存在服務端渲染和客戶端渲染兩種情況,這就要求我們要分別在服務端和客戶端對瀏覽器是否支持Webp作出判斷,如果瀏覽器支持,就去oss取webp格式的圖片,否則繼續使用原本圖片格式。

我所採取的方法是在封裝網路請求的時候,做了一步判斷,然後把是否支持Webp的變數放到了環境變數中。由於網路請求需要同時支持客戶端和服務端,所以我採用的是axios並自己做了一層封裝。

// 封裝axioscreateRequest = (req) => { // 如果在客戶端創建 if (process.client) { process.env.supportWebp = document.createElement(canvas).toDataURL(image/webp).indexOf(data:image/webp) === 0 } else { // 從服務端檢測客戶端是否支持webp if (req && req.headers) { process.env.supportWebp = req.headers.accept.indexOf(image/webp) > -1 }else{ process.env.supportWebp = false } }}

其實無論是客戶端還是服務端,都可以採用判斷accept裡面是否帶有image/webp的方式,但是有些童鞋說判斷accept方式有些瀏覽器不準確,所以我們在客戶端採用較為穩妥的方式去判斷。

每個人的框架或者環境可能不同,所以代碼不一定能照搬,只需理解這部分的思想:根據不同的環境判斷瀏覽器是否支持Webp。

在使用的時候,對於頁面中的img,我寫了一個過濾器:

export function judgeWebp (src) { if(process.env.supportWebp + === true){ return src + ?x-oss-process=image/format,webp } return src}const filters = { //......, judgeWebp}Object.keys(filters).forEach(key => { Vue.filter(key, filters[key])})

對於背景圖片,style動態綁定似乎是不能使用過濾器的,所以採用計算屬性的方式實現。各位看官如果有更好的方法歡迎提出來。

到此為止,我們可以根據瀏覽器是否支持webp來獲取到不同格式的圖片了。另外,有些社區也有過利用第三方polyfill來實現瀏覽器兼容Webp的方案。但是似乎並不是那麼的流行,追求穩妥的情況下,我這裡暫不使用,如果你有過類似的實踐,歡迎與我分享。

http緩存

webp的分享就到這裡,接下來我們簡單聊聊http緩存。http緩存大致分為兩類,一類是強制緩存,另一類叫對比緩存。這兩種緩存方式是可以同時存在的。強制緩存,一聽這名字就威武霸氣,所以它的優先順序也是比較高的,就是說,如果強制緩存生效,對比緩存就不再執行。另一個區別點就是,強制緩存如果生效,就不再和伺服器交互了,對比緩存則需要每次都和伺服器交互協商。

強制緩存

先說強制緩存。瀏覽器向伺服器請求數據,返回的header頭中會攜帶緩存規則。體現在Expires和Cache-Control這兩個屬性當中。

Expires是HTTP 1.0的東西,可以說是歷史遺留產物了。它的值是到期時間,如果請求時間小於這個到期時間,就會採用緩存。我們一眼就能發現這個邏輯其實意義並不大,而且如果服務端和客戶端時間不一致,會有誤差產生。

Cache-Control似乎是為彌補Expires的天生缺陷而生的。它倆如果同時存在,Expires則不會生效。它的取值可以為:

這裡需要區別no-store和no-cache,謹記no-store是不做緩存,而no-cache是使用對比緩存。似乎翻譯過來很像,但是實際效果差很多,對於no-store這種不緩存,除非特殊情況,我們一般不使用。

對比緩存

我們再聊聊對比緩存。對比緩存主要分兩大塊,一塊兒是根據修改時間判斷緩存是否生效,另一塊是通過Etag(個人理解就是個hash值)來判斷。

Last-Modified && If-Modified-Since

Last-Modified是存在於返回的header中的,顧名思義,它告訴我們這個資源的最後修改時間。當瀏覽器再次發起請求的時候,會由If-Modified-Since帶著這個值到伺服器去做對比,如果伺服器發現這個值小於目前伺服器上資源的Last-Modified,則會把新的文件返回,狀態碼200。如果大於等於則只返回攜帶304狀態碼的請求,通知瀏覽器這個值尚未失效。

它的缺點是這裡的時間值只能精確到秒。

Etag && If-None-Match

Etag可以理解為伺服器給資源打的hash值,就類似於我們使用構建工具打包資源文件後面會跟一條常常的字元串一樣,它保證資源文件的唯一性。Etag隨response返回給瀏覽器,同理瀏覽器下一次請求會由If-None-Match攜帶Etag的值去到伺服器作比對。如果發現這個值不存在,說明本地的資源文件已經失效,伺服器返回新的資源文件給客戶端,狀態碼200。反之,返回304通知客戶端資源文件仍然生效。

相較於對比最後修改時間的策略,它的優點在於可以突破精確到秒的限制,另外如果我們有一些定期更新的文件,但是資源內容不變,Etag的優勢就更為明顯了。

這裡要提及的一點是,當Last-Modified和Etag策略同時生效的時候,Etag的優先順序更高。

結語

本來是想記錄一下webp的,但是既然是優化,就順便寫了寫http緩存這塊的內容。除此之外,各位還可以根據實際情況合理配置cdn以及nginx等的緩存,以實現更好的用戶體驗。優化路上無止境,但願我們都能往極致的方向去做。今天就聊到這兒,有什麼說錯的地方還請各位看官批評指正,希望大家多多指教!

作者:志如

鏈接:imooc.com/article/detai

來源:慕課網

本文原創發佈於慕課網 ,轉載請註明出處,謝謝合作


推薦閱讀:

【官方】手記欄目認證作者招募,長期有效,隨時報名!_慕課手記

有獎徵文005期 |人生路上得一良師,是何感受?

HTTP狀態碼釋義

java裡面i++與++i到底哪一種寫法的效率高?

推薦一個簡約漂亮的小程序日曆插件


推薦閱讀:

Memcache,Redis,MongoDB(數據緩存系統)方案對比與分析
緩存和資料庫的交互
HTTP緩存的應用,不僅僅是max-age
提取IE緩存中的「秘密」

TAG:Redis | 緩存 | HTTP |