問你一句:「你知道 HTTP/1.1 該如何優化嗎?」php
我想你第一時間想到的是,使用 KeepAlive 將 HTTP/1.1 從短鏈接改爲長連接。css
這個確實是一個優化的手段,它是從底層的傳輸層這一方向入手的,經過減小 TCP 鏈接創建和斷開的次數,來減小了網絡傳輸的延遲,從而提升 HTTP/1.1 協議的傳輸效率。html
但其實還能夠從其餘方向來優化 HTTP/1.1 協議,好比有以下 3 種優化思路:webpack
下面,就針對這三種思路具體看看有哪些優化方法。git
這個思路你看到是否是以爲很奇怪,不發送 HTTP 請求,那還客戶端還怎麼和服務器交互數據?小林你這不是耍流氓嘛?程序員
冷靜冷靜,你說的沒錯,客戶端固然要向服務器發送請求的。github
可是,對於一些具備重複性的 HTTP 請求,好比每次請求獲得的數據都同樣的,咱們能夠把這對「請求-響應」的數據都緩存在本地,那麼下次就直接讀取本地的數據,沒必要在經過網絡獲取服務器的響應了,這樣的話 HTTP/1.1 的性能確定肉眼可見的提高。web
因此,避免發送 HTTP 請求的方法就是經過緩存技術,HTTP 設計者早在以前就考慮到了這點,所以 HTTP 協議的頭部有很多是針對緩存的字段。算法
那緩存是如何作到的呢?apache
客戶端會把第一次請求以及響應的數據保存在本地磁盤上,其中將請求的 URL 做爲 key,而響應做爲 value,二者造成映射關係。
這樣當後續發起相同的請求時,就能夠先在本地磁盤上經過 key 查到對應的 value,也就是響應,若是找到了,就直接從本地讀取該響應。毋庸置疑,讀取本次磁盤的速度確定比網絡請求快得多,以下圖:
聰明的你可能想到了,萬一緩存的響應不是最新的,而客戶端並不知情,那麼該怎麼辦呢?
放心,這個問題 HTTP 設計者早已考慮到。
因此,服務器在發送 HTTP 響應時,會估算一個過時的時間,並把這個信息放到響應頭部中,這樣客戶端在查看響應頭部的信息時,一旦發現緩存的響應是過時的,則就會從新發送網絡請求。HTTP 關於緩說明會的頭部字段不少,這部份內容留在下次文章,此次暫時不具體說明。
若是客戶端從第一次請求獲得的響應頭部中發現該響應過時了,客戶端從新發送請求,假設服務器上的資源並無變動,仍是老樣子,那麼你以爲還要在服務器的響應帶上這個資源嗎?
很顯然不帶的話,能夠提升 HTTP 協議的性能,那具體如何作到呢?
只須要客戶端在從新發送請求時,在請求的 Etag
頭部帶上第一次請求的響應頭部中的摘要,這個摘要是惟一標識響應的資源,當服務器收到請求後,會將本地資源的摘要與請求中的摘要作個比較。
若是不一樣,那麼說明客戶端的緩存已經沒有價值,服務器在響應中帶上最新的資源。
若是相同,說明客戶端的緩存仍是能夠繼續使用的,那麼服務器僅返回不含有包體的 304 Not Modified
響應,告訴客戶端仍然有效,這樣就能夠減小響應資源在網絡中傳輸的延時,以下圖:
緩存真的是性能優化的一把萬能鑰匙,小到 CPU Cache、Page Cache、Redis Cache,大到 HTTP 協議的緩存。
減小 HTTP 請求次數天然也就提高了 HTTP 性能,能夠從這 3 個方面入手:
咱們先來看看什麼是重定向請求?
服務器上的一個資源可能因爲遷移、維護等緣由從 url1 移至 url2 後,而客戶端不知情,它仍是繼續請求 url1,這時服務器不能粗暴地返回錯誤,而是經過 302
響應碼和 Location
頭部,告訴客戶端該資源已經遷移至 url2 了,因而客戶端須要再發送 url2 請求以得到服務器的資源。
那麼,若是重定向請求越多,那麼客戶端就要屢次發起 HTTP 請求,每一次的 HTTP 請求都得通過網絡,這無疑會越下降網絡性能。
另外,服務端這一方每每不僅有一臺服務器,好比源服務器上一級是代理服務器,而後代理服務器才與客戶端通訊,這時客戶端重定向就會致使客戶端與代理服務器之間須要 2 次消息傳遞,以下圖:
若是重定向的工做交由代理服務器完成,就能減小 HTTP 請求次數了,以下圖:
並且當代理服務器知曉了重定向規則後,能夠進一步減小消息傳遞次數,以下圖:
除了 302
重定向響應碼,還有其餘一些重定向的響應碼,你能夠從下圖看到:
其中,301
和 308
響應碼是告訴客戶端能夠將重定向響應緩存到本地磁盤,以後客戶端就自動用 url2 替代 url1 訪問服務器的資源。
若是把多個訪問小文件的請求合併成一個大的請求,雖然傳輸的總資源仍是同樣,可是減小請求,也就意味着減小了重複發送的 HTTP 頭部。
另外因爲 HTTP/1.1 是請求響應模型,若是第一個發送的請求,未收到對應的響應,那麼後續的請求就不會發送,因而爲了防止單個請求的阻塞,因此通常瀏覽器會同時發起 5-6 個請求,每個請求都是不一樣的 TCP 鏈接,那麼若是合併了請求,也就會減小 TCP 鏈接的數量,於是省去了 TCP 握手和慢啓動過程耗費的時間。
接下來,具體看看合併請求的幾種方式。
有的網頁會含有不少小圖片、小圖標,有多少個小圖片,客戶端就要發起多少次請求。那麼對於這些小圖片,咱們能夠考慮使用 CSS Image Sprites
技術把它們合成一個大圖片,這樣瀏覽器就能夠用一次請求得到一個大圖片,而後再根據 CSS 數據把大圖片切割成多張小圖片。
這種方式就是經過將多個小圖片合併成一個大圖片來減小 HTTP 請求的次數,以減小 HTTP 請求的次數,從而減小網絡的開銷。
除了將小圖片合併成大圖片的方式,還有服務端使用 webpack
等打包工具將 js、css 等資源合併打包成大文件,也是能達到相似的效果。
另外,還能夠將圖片的二進制數據用 base64
編碼後,以 URL 的形式潛入到 HTML 文件,跟隨 HTML 文件一併發送.
<image src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAAFKCAIAAAC7M9WrAAAACXBIWXMAA ... />
這樣客戶端收到 HTML 後,就能夠直接解碼出數據,而後直接顯示圖片,就不用再發起圖片相關的請求,這樣便減小了請求的次數。
圖來源於:陳健平的CSDN能夠看到,合併請求的方式就是合併資源,以一個大資源的請求替換多個小資源的請求。
可是這樣的合併請求會帶來新的問題,當大資源中的某一個小資源發生變化後,客戶端必須從新下載整個完整的大資源文件,這顯然帶來了額外的網絡消耗。
不要一口氣吃成大胖子,通常 HTML 裏會含有不少 HTTP 的 URL,當前不須要的資源,咱們不必也獲取過來,因而能夠經過「按需獲取」的方式,來減小第一時間的 HTTP 請求次數。
請求網頁的時候,不必把所有資源都獲取到,而是隻獲取當前用戶所看到的頁面資源,當用戶向下滑動頁面的時候,再向服務器獲取接下來的資源,這樣就達到了延遲發送請求的效果。
對於 HTTP 的請求和響應,一般 HTTP 的響應的數據大小會比較大,也就是服務器返回的資源會比較大。
因而,咱們能夠考慮對響應的資源進行壓縮,這樣就能夠減小響應的數據大小,從而提升網絡傳輸的效率。
壓縮的方式通常分爲 2 種,分別是:
無損壓縮是指資源通過壓縮後,信息不被破壞,還能徹底恢復到壓縮前的原樣,適合用在文本文件、程序可執行文件、程序源代碼。
首先,咱們針對代碼的語法規則進行壓縮,由於一般代碼文件都有不少換行符或者空格,這些是爲了幫助程序員更好的閱讀,可是機器執行時並不要這些符,把這些多餘的符號給去除掉。
接下來,就是無損壓縮了,須要對原始資源創建統計模型,利用這個統計模型,將常出現的數據用較短的二進制比特序列表示,將不常出現的數據用較長的二進制比特序列表示,生成二進制比特序列通常是「霍夫曼編碼」算法。
gzip 就是比較常見的無損壓縮。客戶端支持的壓縮算法,會在 HTTP 請求中經過頭部中的 Accept-Encoding
字段告訴服務器:
Accept-Encoding: gzip, deflate, br
服務器收到後,會從中選擇一個服務器支持的或者合適的壓縮算法,而後使用此壓縮算法對響應資源進行壓縮,最後經過響應頭部中的 content-encoding
字段告訴客戶端該資源使用的壓縮算法。
content-encoding: gzip
gzip 的壓縮效率相比 Google 推出的 Brotli 算法仍是差點意思,也就是上文中的 br,因此若是能夠,服務器應該選擇壓縮效率更高的 br 壓縮算法。
與無損壓縮相對的就是有損壓縮,通過此方法壓縮,解壓的數據會與原始數據不一樣可是很是接近。
有損壓縮主要將次要的數據捨棄,犧牲一些質量來減小數據量、提升壓縮比,這種方法常常用於壓縮多媒體數據,好比音頻、視頻、圖片。
能夠經過 HTTP 請求頭部中的 Accept
字段裏的「 q 質量因子」,告訴服務器指望的資源質量。
Accept: audio/*; q=0.2, audio/basic
關於圖片的壓縮,目前壓縮比較高的是 Google 推出的 WebP 格式,它與常見的 Png 格式圖片的壓縮比例對好比下圖:
來源於:https://isparta.github.io/compare-webp/index.html能夠發現,相同圖片質量下,WebP 格式的圖片大小都比 Png 格式的圖片小,因此對於大量圖片的網站,能夠考慮使用 WebP 格式的圖片,這將大幅度提高網絡傳輸的性能。
關於音視頻的壓縮,音視頻主要是動態的,每一個幀都有時序的關係,一般時間連續的幀之間的變化是很小的。
好比,一個在看書的視頻,畫面一般只有人物的手和書桌上的書是會有變化的,而其餘地方一般都是靜態的,因而只須要在一個靜態的關鍵幀,使用增量數據來表達後續的幀,這樣便減小了不少數據,提升了網絡傳輸的性能。對於視頻常見的編碼格式有 H26四、H265 等,音頻常見的編碼格式有 AAC、AC3。
此次主要從 3 個方面介紹了優化 HTTP/1.1 協議的思路。
第一個思路是,經過緩存技術來避免發送 HTTP 請求。客戶端收到第一個請求的響應後,能夠將其緩存在本地磁盤,下次請求的時候,若是緩存沒過時,就直接讀取本地緩存的響應數據。若是緩存過時,客戶端發送請求的時候帶上響應數據的摘要,服務器比對後發現資源沒有變化,就發出不帶包體的 304 響應,告訴客戶端緩存的響應仍然有效。
第二個思路是,減小 HTTP 請求的次數,有如下的方法:
第三思路是,經過壓縮響應資源,下降傳輸資源的大小,從而提升傳輸效率,因此應當選擇更優秀的壓縮算法。
無論怎麼優化 HTTP/1.1 協議都是有限的,否則也不會出現 HTTP/2 和 HTTP/3 協議,後續咱們再來介紹 HTTP/2 和 HTTP/3 協議。
好了,這次分享到這就結束了,若是這篇文章對你有幫助,歡迎來個三連,大家的支持就是小林的最大動力,咱們下次見!