從用戶的角度出發,得益於各大瀏覽器廠商的不懈努力,這一切都顯得已經很理所固然,輸入一個地址,訪問網絡,顯示一個絢麗多彩的界面,你能夠能夠在上面瀏覽視頻,看文章,甚至玩遊戲。
可是站在開發者的角度,這是一個縱觀全局的大問題,每個步驟都是一個能夠延伸的話題。對於項目的優化都離不開這裏的方方面面,是有深刻理解的價值的。咱們能夠從一個總覽出發,看看背後發生了什麼。
首先咱們要知道什麼是DNSweb
域名系統(英文:Domain Name System,縮寫:DNS)是互聯網的一項服務。它做爲將域名和IP地址相互映射的一個分佈式數據庫,可以令人更方便地訪問互聯網。DNS使用TCP和UDP端口53。當前,對於每一級域名長度的限制是63個字符,域名總長度則不能超過253個字符。 --維基百科
域名解析的過程是逐級查詢的chrome
dscacheutil -flushcache
咱們能夠經過dig命令查看域名解析的記錄數據庫
dig math.stackexchange.com
咱們重點看返回的應答,會看到有四條記錄,返回了該網址的四個IPsegmentfault
;; ANSWER SECTION: math.stackexchange.com. 31 IN A 151.101.1.69 math.stackexchange.com. 31 IN A 151.101.129.69 math.stackexchange.com. 31 IN A 151.101.193.69 math.stackexchange.com. 31 IN A 151.101.65.69
31是TTL的值,表示該域名的緩存時間,即該時間內不用從新查詢。A是該DNS查詢的記錄類型,表示返回一個IPv4格式的地址。還有其餘記錄類型諸如 NS(返回查詢的服務器地址)、AAAA(返回IPV6格式的地址)、CNAME(域名的別名)等。瀏覽器
拿到了要請求的資源服務器IP後,瀏覽器經過操做OS的socket與服務器進行TCP鏈接(通常來講操做系統已經封裝好了TCP/IP等協議,提供套接字給應用去使用,該部分涉及到標準網絡模型的知識,另外再開篇拓展。)緩存
這個鏈接就是咱們所熟知的三次握手
本機主動打開鏈接服務器
須要注意的一點是,有一些文章對ACK標識位 和 ack(Acknowledgement Number)的解釋比較模糊,有一些畫圖的時候乾脆就寫在一塊兒了。雖然這二者有關聯,但不是同一個東西,搞清楚這個誤區能夠更方便去理解。還有一些會把第二次握手描述成兩個包(好比某百科……),實際上這也是不正確的網絡
理解了這兩點,也就不難理解爲何三次握手分別是SYN、ACK/SYN、ACK了。併發
TCP的頭部固定有20個字節,其中分配了6bits給TCP FLAG,組合起來用來表示當前包的類型。分別是
URGACKPSHRSTSYNFIN(CWRECE放在保留位,暫不考慮)socket
至此咱們瞭解了一個TCP 鏈接的過程,通道通了,是時候利用這個通道送東西了。
咱們從傳輸層再回到應用層。
超文本傳輸協議(英文:HyperText Transfer Protocol,縮寫:HTTP)是一種用於分佈式、協做式和超媒體信息系統的應用層協議[1]。HTTP是萬維網的數據通訊的基礎。設計HTTP最初的目的是爲了提供一種發佈和接收HTML頁面的方法。經過HTTP或者HTTPS協議請求的資源由統一資源標識符(Uniform Resource Identifiers,URI)來標識。 --wiki
咱們用 https://www.segmentfault.com 舉例子。
在應用層,瀏覽器會分析這個url,並設置好請求報文發出。請求報文中包括請求行、請求頭、空行、請求主體。https默認請求端口443, http默認80。
服務端收到請求以後,會根據url匹配到的路徑作相應的處理,最後返回瀏覽器須要的頁面資源。瀏覽器會收到一個響應報文,而所須要的資源就就在報文主體上。與請求報文相同,響應報文也有與之對應的起始行、首部、空行、報文主體,不一樣的地方在於包含的東西不同。
請求是瀏覽器的一個優化點,咱們能夠經過緩存來減小沒必要要的請求,進而加快頁面的呈現。經過簡單地設置http頭部可使用緩存的功能。通常來講有三種設置的方式
服務器在返回資源的時候設置Last-Modify當前資源最後一次修改的時間,瀏覽器會把這個時間保存下來,在下次請求的時候,請求頭部If-Modified-Since 會包含這個時間,服務端收到請求後,會比對資源最後更新的時間是否在If-Modified-Since設置的時間以後,若是不是,返回304狀態碼,瀏覽器將從緩存中獲取資源。反之返回200和資源內容。
根據資源標識符來肯定文件是否存在修改,服務器每一次返回資源,都會在Etag中存放資源的標識符,瀏覽器收到這個標識符,在下一次請求的時候將標識符放在If-None-Match中,服務端將判斷是否匹配,若是不匹配,返回200以及新的資源,反之返回304,瀏覽器從緩存中獲取資源
首先這不是一種方法,而是協議更替中的一種演化。
在http 1.0的時代,咱們基於Pragma 和 Expires 控制緩存的生命週期。咱們能夠經過設置Pragma爲no-cache關閉緩存功能,一樣也能夠在Expires中設置一個緩存失效的時間。須要注意的是,這個失效的時間是相對於服務器的實踐而言的,若是人爲地改變了客戶端的時間,是會致使緩存失效的。
因此,爲了解決這個問題,HTTP1.1的協議加入了Cache-Control,經過設置Cache-Control的max-age能夠控制緩存的週期。在這個週期內,資源是新鮮的,瀏覽器再一次須要使用資源的時候,就不會發出請求了。
至此瀏覽器已經拿到了一個HTML文檔,併爲了呈現文檔而開始解析。呈現引擎開始工做,基本流程以下(以webkit爲例)
從構建DOM樹到呈現的過程以下
op=>operation: Parsing HTML to construct the DOM tree op1=>operation: Render Tree construction op2=>operation: Layout of the Render Tree op3=>operation: Painting the Render Tree op->op1->op2->op3
須要注意的是,這是一個漸進的過程,呈現引擎爲了力求顯示的及時,會在文檔請求不徹底的狀況下就開始渲染頁面,同時,若是在解析的過程當中遇到script的時候,文檔的解析將會中止下來,當即解析執行腳本,若是腳本是外部的,則會等待請求完成並解析執行。因此,爲了避免阻塞頁面地呈現,通常會把script腳本放在文檔的最後。
在最新的HTML4和HTML5規範中,也能夠將腳本標註爲defer,這樣就不會中止文檔解析,而是等到解析結束後才執行。HTML5 增長了一個選項,可將腳本標記爲async,以便由其餘線程解析和執行。
如今的頁面爲了優化請求的耗時,默認都會開啓持久鏈接(keep-alive),那麼一個TCP鏈接確切關閉的時機,是這個tab標籤頁關閉的時候。這個關閉的過程就是著名的四次揮手。關閉是一個全雙工的過程,發包的順序的不必定的。通常來講是客戶端主動發起的關閉,過程以下。
假如最後一次客戶端發出的數據seq = x, ack = y;
MSL: 全程Maximum Segment Lifetime,中文能夠翻譯爲報文最大生存時間。等待是爲了保證鏈接的可靠性,確保服務端收到ACK包,若是服務端沒有收到這個ACK包,將會重發FIN包給客戶端,而這個時間恰好是服務端等待超時重發的時間 + FIN的傳輸時間。