構建高效能WEB之HTTP首部優化

十三號線上的螻蟻發表於2015-10-03

0×00 前言

在討論瀏覽器優化之前,首先我們先分析下從客戶端發起一個HTTP請求到使用者接收到響應之間,都發生了什麼?知己知彼,才能百戰不殆。這也是作為一個WEB開發者,為什麼一定要深入學習TCP/IP等網路知識

0×01 到底發生什麼了?

當使用者發起一個HTTP請求時,首先客戶端將與服務端之間建立TCP連線,成功建立連線後,服務端將對請求進行處理,並對客戶端做出響應,響應內容一般包括響應主體。
(此處我們僅簡單說明,但真實的一次請求其中發生的事情是相當複雜的,這裡貼條連線,講得比較詳細)。
從輸入 URL 到頁面載入完成的過程中都發生了什麼事情?

建立TCP連線

為了進行可靠的資料傳輸,TCP在進行傳送資料之前,會進行TCP三次握手,以此確定接收方能夠成功收取傳輸的資料,而建立連線的過程,必然是要耗費系統資源,以及時間資源的。

服務端處理並響應

當服務端接收到客戶端傳送來的請求之後,如果請求內容是靜態資源,服務端會從硬碟中取出靜態資源,然後將靜態資源放在響應主體中,傳送給客戶端。如果是動態資源,服務端首先取出資源,並通過業務邏輯操作,動態生成最終的響應主體,然後傳送給客戶端。

客戶端渲染

客戶端接受到服務端傳輸過來的網路資源,然後進行渲染,繪製等,最終展示給使用者。

0×02 優化點在哪裡?

通過簡單的瞭解,我們瞭解到TCP建立連線是有資源消耗,時間消耗的,那麼如果我們無需每次簡歷TCP連線,那是否可以提高網站的效能呢?答案是肯定的。

  • 優化點1:減少TCP連線

我們知道,在獲取資源的時候,以獲取速度從慢到快是:網路資源->本地硬碟資源->本地記憶體資源。而網路資源也分硬碟資源以及記憶體資源。並且網路資源的傳輸,也是有相當大的時延的。

  • 優化點2:對資料進行快取
  • 優化點3:減少資料傳輸量

0×03 如何進行優化?

本篇文章主要說的優化點是與HTTP首部有關的優化,或者說是與瀏覽器端有關的優化,其它優化這裡暫不贅述。

持久連線:Keep-Alive

HTTP連線設計之初是請求-響應-關閉,也就是每建立一次HTTP連線,只能進行一次資源請求,當需要在同一目標伺服器上獲取多個資源的時候,就需要多次建立HTTP連線,而這個多次建立連線的過程,便降低了網站的效能。

於是,出現了Connection:Keep-Alive,人稱持久連線。Keep-Alive避免了建立或者說重新建立連線的過程,減少了HTTP連線。

而與此配套的有Keep-Alive:timeout=120,max=5

其中,timeout=120 是指這個TCP通道保持120S,max=5 指這個TCP通道最多接收5個HTTP請求,之後便自動關閉該連線。

修改時間:Last-Modified 和 If-Modified-Since

Last-Modified首部是服務端對客戶端的HTTP響應所加的一個與快取有關的HTTP首部,該首部標記了所請求資源在服務端的最後修改時間。類似:

Last-Modified : Fri , 12 May 2015 13:10:33 GMT

當客戶端發現HTTP響應頭中有Last-Modified,會對資源進行快取,在下次請求資源時,在HTTP請求頭中新增If-Modified-Since首部,首部中將會新增上次成功請求資源時響應頭部的Last-Modified屬性值,即:

If-Modified-Since : Fri , 12 May 2015 13:10:33 GMT

當服務端接收到的HTTP請求中,發現有If-Modified-Since頭部時,會將該屬性值與請求資源的最後修改時間進行比對,如果最後修改時間與該屬性值一致時,服務端會返回一個304 Not Modified響應,該響應中不包括響應實體。瀏覽器收到304的響應後,會進行重定向,獲取本地快取資源。如果最後修改時間與該屬性值不一致,則會從服務端重新獲取資源,做出200響應。

版本標記:ETag 和 If-None-Match

ETag其實與Last-Modified是差不多的方式,但是ETag並沒有選擇以時間作為標記,而是對所請求檔案進行某些演算法來生成一串唯一的字串,作為對某一檔案的標記。當收到客戶端對某一資源的請求時,服務端在響應時,新增ETag首部,如下:

ETag:W/"a627ff1c9e65d2dede2efe0dd25efb8c"

當客戶端發現ETag頭部時,同樣會對資源進行快取,並在下次請求時,在請求頭部新增If-None-Match,如:

If-None-Match:W/"a627ff1c9e65d2dede2efe0dd25efb8c"

當服務端收到請求中含有該頭部時,會使用同樣的ETag生成演算法對檔案ETag進行計算,並與If-None-Match屬性值進行比對,如果一致,則返回一個304 Not Modified響應,基本與上一種方式是一致的。

快取時間:Expires 和 Cache-Control

上述兩種方式中,每次請求資源時,雖然在有快取的情況下,選擇快取進行渲染繪製,但是在這之前還是發起了一次HTTP請求,雖然並沒有真實的響應實體,但是依然會造成一些資源消耗。而Expires與上述兩種方式使用了不同的思路。

當服務端希望客戶端瀏覽器對某一資源進行快取時,為了免去客戶端每次都要詢問自己:我上次的快取現在還能用嗎?所以,服務端選擇了放權。只去告訴瀏覽器,我這次給你的資源你可以用多長時間,在這個時間段內,你可以一直使用它,無需每次諮詢我。而服務端就是通過Expires屬性來告訴客戶端瀏覽器可以多長時間內不需要詢問服務端。如下:
Expires:Thu, 19 Nov 2015 15:00:00 GMT

當客戶端在響應首部中發現該屬性值時,便會將該資源快取起來,而快取的過期時間即是Expires中的時間。在這個時間段內,瀏覽器完全自主。

但是,Expires有一個不足的地方是,如果服務端時間與客戶端本地時間不統一時,可能服務端讓客戶端可以對該資源快取一個小時,而客戶端本地時間比服務端時間快了兩個小時,那就意味著,所有快取都將不會生效。

於是有了彌補該不足的一個屬性,即:Cache-Control。如果服務端在響應首部新增該屬性時,客戶端將直接使用該屬性值來生成本地時間的快取過期時間,這樣便解決了這個問題,如下:

Cache-Control:max-age=3600

如果客戶端在2015年10月01日13時00分00秒收到該響應時,便會加上3600秒也就是2015年10月01日14時00分00秒作為快取過期時間。如果響應頭部既有ExpiresCache-Control,瀏覽器會首選Cache-Control

0×04 結束

這裡,基本上說的都是與HTTP首部有關的網站效能優化。本文主要是在對《構建高效能WEB站點. 郭欣著》中第六章瀏覽器快取的學習總結筆記。這本書對於WEB站點的優化,從各個層面都做了很詳盡的講解,確實是一本很棒的書,也在這裡感謝HQBOSS的推薦。

相關文章