對於http/http2的一些總結

大雄沒了哆啦A夢發表於2018-08-25

http是前端面試當中經常會被問到的,雖然前端對http的運用不是很多,但是對於前端來說,http的優化,http的除錯,看懂一些http的原理還是很有必要的

http快取

http的快取,是前端優化的一種很有效的方式,通過設定http快取,可以做到不需要去伺服器請求資源,做到減少http請求的效果,從而達到提高網站響應速度的優化。http快取中,存在強制快取和協商快取。其實這兩種快取都是需要在伺服器端設定的,但是前端也需要了解這方面的知識,所以略做了解。

強制快取

強制快取伺服器的response告訴瀏覽器,這個資源到什麼時候為止/過多久才過期,在這段時間內,不需要到我這裡來獲取,如果我們的資源很少改變的情況下,建議在伺服器這邊設定過期時間長點。
expires: 在http1.0的,可以通過expires設定過期時間(具體時間),告訴瀏覽器快取到什麼時候為止。缺點是伺服器時間和瀏覽器時間可能不同步,或者一方時間不準,那麼快取設定的時間就不對了。
cache-control: max-age,在http1.1中,通過設定response的cache-control的max-age告訴瀏覽器,過多久才過期,是基於瀏覽器的時間的,所以快取過期時間始終是對的。
強制快取能命中的話,瀏覽器會返回200(from disk cache)的狀態碼。

對於http/http2的一些總結
image

這裡多說一句,如果你想要避免瀏覽器快取的話,可以改變請求資源的url,比如加上雜湊值,這也是現在用的很多的方式。

<script src="http://..../detail.build.469ee1c5.js"></script>
複製程式碼

協商快取

協商快取,是伺服器告訴瀏覽器一些唯一的標識(ETag)或者檔案最後修改時間(Last-Modified),來讓瀏覽器判斷資源是否在伺服器端改變了,從而決定讀取的資源是從快取中還是從瀏覽器返回的response中讀取。

last-modified/if-since-last-modified,瀏覽器第一次請求伺服器資源的時候,伺服器會通過response返回返回資源最新的修改時間(last-modified)給瀏覽器,瀏覽器儲存這個時間,然後下次請求的時候,在請求頭部中將該時間設定到if-since-last-modified中,伺服器接收到這個請求,發現有if-since-last-modified的快取驗證時,驗證快取的新鮮度(通過判斷伺服器上的資源的最後更新時間與if-since-last-modified的時間對比),如果新鮮,則返回304的狀態碼。瀏覽器解析到304的狀態碼,直接讀取快取。

image
etag/if-none-match,瀏覽器第一次請求伺服器資源時,伺服器會在通過response返回該資源內容對應的雜湊值(etag),瀏覽器儲存這個值,下次請求的時候,將請求頭if-none-match設定為該值,伺服器接收到這個請求,發現有if-none-match的快取驗證時,驗證快取的新鮮度(通過判斷伺服器上的資源內容的雜湊值和if-none-match的進行對比),如果新鮮,則返回304的狀態碼。瀏覽器解析到304的狀態碼,直接讀取快取。
image

last-modified vs etag

last-modified是基於時間的,只能精確到秒,如果資源修改得很頻繁,那麼有可能內容已經修改了,但是秒數還沒更新到,那麼瀏覽器就會誤以為沒有更新,直接讀取快取了。還有一點,如果資源的內容沒有改變,但是最後修改時間改變了,那麼瀏覽器也會誤以為資源沒更新。而etag正好克服了last-modified的缺點。因此,建立開啟etag的協商快取。

http驗證的流程圖:

image

http1.0和http1.1

我們知道,http是建立在TCP連線上的,即先要通過三次握手建立TCP連線,然後再傳送http請求。在http1.0中,一個http當中只能一個request和一個response,然後TCP就關閉,下次再傳送http,需要再建立TCP連線,所以http請求一多,TCP建立和關閉就會很頻繁,很浪費資源。所以,在http1.1當中,通過connection: keep-alive可以實現一個TCP連線中,可以傳送多個http請求,這樣瀏覽器可以繼續通過相同的TCP連線傳送多次請求,可以避免多次建立/釋放tcp帶來的損耗。

優點:一次TCP連線中可以傳送多次http請求,所以避節省每次傳送http都要建立TCP連線的時間和寬頻。
缺點:TCP長時間的連線,容易導致系統的資源的無效佔用,浪費系統資源。

網上有個總結:
1、當你的Server記憶體充足時,KeepAlive =On還是Off對系統效能影響不大。
2、當你的Server上靜態網頁(Html、圖片、Css、Js)居多時,建議開啟KeepAlive 。
3、當你的Server多為動態請求(連線資料庫,對檔案系統訪問較多),KeepAlive 關掉,會節省一定的記憶體,節省的記憶體正好可以作為檔案系統的Cache(vmstat命令中cache一列),降低I/O壓力。

還有一點,http1.1新增了Cache-Control的max-age來進行http的強快取,使用想對時間,單位是s,克服了http1.0中的expired的使用具體時間,如果時間表示出錯或者沒有轉換到正確的時區都可能造成快取生命週期出錯問題。

http2.0和http1.0

1、http2是採用二進位制進行傳輸資料的,而http1是文字傳輸,對比起來二進位制傳輸的解析和優化上更具有優勢,什麼優勢下面會講到(可以分幀,並行請求)。
2、http2對頭部進行的壓縮,能夠減少頭部佔用的網路流量。
3、http2實現了多路複用,同一域名不管傳送多少請求,也只建立一路連線,這樣就突破了瀏覽器對同一域名併發數的限制了。
4、http2支出伺服器端推送。

http1.1 keep-alive和http2多路複用的區別

我們很容易混淆這兩者的區別,會誤以為兩者都是在一個TCP中,可以傳送多次http請求/接受http響應的,但實際上,兩者存在著本質上的區別,看網上的一張圖:

對於http/http2的一些總結

從圖中大家應該能分清楚差別了吧。keep-alive雖然能夠使得一次TCP連線傳送多次http請求,但是因為http1是基於文字傳輸的,是序列的檔案傳輸,所以必須保證傳輸的順序,因此一個請求必須等待另一個請求完成以後才能繼續,請求是序列的。

http1.1的keep-alive只是避免在每次請求當中,都重新開啟一個TCP連線,避免TCP連線所帶來的時間和寬頻的消耗,但每個http請求還是序列傳送的,很容易造成堵塞。所以為了提高頁面響應速度,於是有了併發開啟多個TCP連線的優化,並行建立多個TCP連線,但基於開啟TCP連線需要消耗CPU和記憶體等系統資源,所以瀏覽器都對TCP的併發有限制,一般限制為6個,伺服器也對TCP的連線數也是有限制的。
回到http2,我們知道http2是二進位制傳輸資料的,資料是以幀為單位傳送的(當然每個幀都是有順序標識的,確保伺服器接收後能恢復順序),一個請求(訊息)被分為一塊一塊的幀進行傳送,這些幀可以交錯傳送,不管是哪個請求的幀都可以交錯傳送(http2中的幀包含的http頭部資訊等,確保幀最後能夠恢復成訊息),因此可以做到並行傳送請求,避免擁堵。

關於兩者在一個tcp連線中能傳送多少個http請求的問題,http1.1當中是按時間來算的,一定時間內,同一域名只建立一次TCP連線,這段時間的http請求在這個TCP連線的基礎上傳送和響應,以達到提高請求效率的問題。而http2的請求是基於流的,即所有的請求都共用一個tcp連線,一個http請求就是一個流,一個 TCP 連線成,可以承載任意數量的資料流。

對於http/http2的一些總結

最後我們通過網上的兩張圖檢視下區別:

對於http/http2的一些總結
htt1,序列請求,一個請求的傳送,必須等待一個請求響應後才能開始。

對於http/http2的一些總結
http2,並行請求,所有請求被劃分為一個一個的幀一次性全部發出去。

關於http post和get請求的區別

GET在瀏覽器回退時是無害的,而POST會再次提交請求。
GET產生的URL地址可以被Bookmark,而POST不可以。
GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。
GET請求只能進行url編碼,而POST支援多種編碼方式。
GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留。
GET請求在URL中傳送的引數是有長度限制的,而POST麼有。
對引數的資料型別,GET只接受ASCII字元,而POST沒有限制。
GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊。
GET引數通過URL傳遞,POST放在Request body中。
(本標準答案參考自w3schools)

狀態碼

100 繼續,http POST請求有時會傳送兩次tcp包,一次header一次body,第一次伺服器會返回100的狀態碼,告訴瀏覽器可以傳送body了
101 協議升級,比如升級為websocket

200 ok,也可以是快取命中返回的狀態碼

301 暫時重定向 302 永久重定向 304 協商快取,伺服器告訴瀏覽器從快取中讀取

400 請求無效,和伺服器端沒對應起來
401 需要使用者驗證
403 伺服器端已接收到,但拒絕執行

500 伺服器錯誤

從瀏覽器輸入url到顯示頁面的整個流程

1、檢視有快取,有快取且未過期,直接讀取快取
2、瀏覽器解析url,組裝成一個http報文
3、解析域名下的ip地址(DNS查詢)
4、開啟一個socket與目標ip、埠建立tcp連線
5、傳送http請求到伺服器
6、伺服器解析請求,並將請求轉發到對應的處理程式當中
7、伺服器檢查http中是否有快取驗證資訊,判斷快取是否新鮮,如果新鮮返回304狀態碼
8、處理程式處理完資料,準備http響應
9、伺服器將http響應報文通過tcp連線傳送回瀏覽器
10、瀏覽器接收http響應,根據情況關閉tcp連線或者保留重用(keep-alive)
11、瀏覽器檢查http狀態碼
12、判斷資源是否可以快取,可以的話進行快取
13、對響應進行解碼(gzip解碼)
14、根據資源型別決定如何處理,如果是js的話,則下載執行,如果是html的話,則交給瀏覽器進行渲染顯示

websocket的實現原理

websocket的實現是基於http的,用http實現握手,然後使用TCP的全雙工通訊的協議,這樣就可以實現客戶端和伺服器端的長連線,實現實時通訊。要支援websocket必須在http1.1中使用以下兩個屬性:
Connection: upgrade
Upgrade: websocket

Connection為upgrade告訴伺服器,我不在使用http了,要升級協議了,伺服器不需要轉發upgrade所在的域;upgrade告訴伺服器,客戶端希望使用建立好的TCP連線,切換到websocket協議(http/websocket都是基於tcp的)。

這邊文章是通過閱讀網上關於http的一個總結,加上自己的理解寫成的,如果有什麼不對的,歡迎在評論中指正。
參考連結:
developers.google.com/web/fundame…
web.jobbole.com/92773/
segmentfault.com/a/119000001…

相關文章