面試常問:超詳細擴展解讀瀏覽器輸入URL後發生了什麼

經過對書籍和各類資料的整理加上本身的理解總結以下,有不對或者不許確的地方你們指出及時更正。css

先說發生了哪些步驟

  • 瀏覽器主進程網絡模塊接管獲取資源
  • DNS查詢獲取域名對應的ip地址
  • 與目標服務器創建TCP鏈接
  • https協議會進行ssl握手
  • 向目標服務器發起http請求
  • 服務器處理請求並返回http響應
  • 瀏覽器進行渲染顯示內容並獲取其餘資源並執行js腳本(包括js執行機制和緩存內容)

每步詳解:

一.瀏覽器相關

以前一直了解瀏覽器發起請求去獲取資源,可是一直不知道瀏覽器具體是怎麼發起請求靠什麼發起請求,因此 首先了解瀏覽器的結構,瀏覽器是多進程多線程架構,主要包括:html

Browser進程(瀏覽器主進程):

  • 與用戶交互(前進後退等)
  • 負責各個進程的管理,是其餘進程的祖先,有且只有一個
  • 網絡資源的下載
  • 負責瀏覽器界面的顯示,將render進程獲得的BitMap繪製到界面上

render進程(能夠理解爲每個打開的tab頁):

  • 網頁的渲染進程,負責頁面的渲染工做,渲染和繪製不同,渲染獲得bitmap交給主進程繪製
  • 內部多線程,包括GUI渲染線程,js引擎線程,事件觸發線程,定時器線程,http線程

GPU進程:

  • 最多隻有一個,當且僅當GPU硬件加速打開的時候纔會被建立,主要用於對3D圖形加速。

上圖中的連線表明進程間的通訊,若是沒有代表兩種不一樣類型進程之間沒有通訊。進程間通訊好比說Browser進程和Renderer進程依賴於Browser進程中的RenderHost接口和Renderer進程中的renderer接口通訊。須要着重理解的一點事,Renderer進程在網頁的加載執行中須要獲取資源好比須要html,css,js或者ajax請求,Renderer進程是沒有權限去獲取資源的,處於安全性和資源共享等問題,Renderer進程中的資源其實是經過進程間通訊將任務交給Browser進程來完成的。linux

發起的http請求的是主進程中的網絡模塊,它承擔了創建網絡鏈接,發送請求數據和接收數據的任務,還包括對http協議,dns解析,ssl等網絡方面的支持。webpack

二.DNS尋址

請求一旦發起,在TCP鏈接前,瀏覽器首先要作的是域名解析,也就是找到域名對應的IP地址。DNS是域名系統是保存着ip地址和域名映射關係的一個分佈式數據庫。首先了解幾個概念:web

  • 根DNS服務器: 有13個根DNS服務器(A-M),能夠將13個根DNS服務器視爲單個服務器,實際上每臺服務器是服務器集羣 *頂級域名服務器(TLD): 這些服務器負責頂級域名(com,org,net等)
  • 權威DNS服務器: 因特網上具備公共可訪問主機(web服務器)的每一個組織機構必須提供可訪問的DNS記錄,這些記錄是域名和IP地址的映射,權威DNS服務器負責保存這些DNS記錄。組織結構能夠選擇實現本身的權威DNS服務器來板保存本身的DNS映射,也能夠選擇支付費用儲存在服務商的權威DNS服務器中。
  • 本地DNS服務器: 當你的電腦經過電信運營商接入網絡後,電信運營商會分配給你一個DNS服務器,通常爲上網默認的DNS服務器,一般就是你電腦或者手機網絡設置設置的DNS服務器(通常都是自動獲取),它能夠幫你迭代解析查詢。
    還有一種狀況是,好比說當你遭遇了電信運營商的DNS劫持也就是篡改了某個域名的ip解析結果指向了另外一個網站,你能夠把手機或電腦裏的DNS配置改成114.114.114.114也就是114DNS服務器,是一個第三方可靠的DNS服務平臺。

DNS記錄:每一個DNS應答報文包含一條或多條資源記錄,格式爲{name, value, type ,ttl}

  • A記錄: A記錄指的是域名直接和IP映射,name爲域名,value爲域名對應的ip地址,{xxx.com, 11.11.11.11,A}
  • CNAME: CNAME指的是域名和域名映射也就是別名,name爲別名,value爲主機名 {'cname', xxx.com, cname}
  • NS記錄: NS記錄指的是由哪臺服務器對該域名進行解析,name是域,value被指向的域名,{xxx.com,dns.xxx.com,NS}
  • 註冊域名後再數據庫中插入DNS記錄的過程: 當向某些註冊登記機構註冊域名xxx.com的時候,須要向其提供你的權威DNS服務器的域名和IP,假設域名是dns1.xxx.com,ip爲111.111.111.111,機構確保將一個NS記錄如{xxx.com, dns1.xxx.xom, NS}和一個A記錄如{dns1.xxx.com,111.111.111.111,A}輸入com的頂級域名服務器,你也必須確保www.xxx.com的A記錄輸入你的權威DNS服務器中。

DNS查找過程

  • 1.瀏覽器DNS緩存

由於瀏覽器網絡模塊中的HostCache類用來保存解析後的域名。因此先查詢瀏覽器DNS緩存可否命中,命中就返回ajax

  • 2.系統DNS緩存

linux系統中就是/etc/hosts文件,命中返回算法

  • 3.本地DNS服務器或者網絡設置的DNS服務器

先檢查可否命中緩存,命中返回,此時拿到的ip地址被標記爲非權威服務器應答,終端向本地DNS服務器的查詢是遞歸查詢,所謂的遞歸查詢就是終端向本地DNS服務器查詢沒有獲得結果,本地DNS服務器就繼續發出查詢請求,而不是讓終端本身進行下一步查詢,因此遞歸查詢返回的是結果IP地址或者報錯。客戶端只發一次請求,要求對方給出結果。數據庫

  • 4.本地DNS服務器向根域名服務器迭代查詢

迭代查詢能夠理解爲經歷不少的指引操做,本地DNS服務器向根域名服務器查詢的過程爲迭代查詢,根域名服務器收到本地DNS服務器的請求時告訴本地DNS服務器你下一步應該去哪個域名服務器查詢,而後本地服務器繼續查詢。若是沒有在本地DNS服務器命中緩存則在本地DNS服務器的配置文件中找到13個根域名服務器的地址而後向其發起請求,根域名服務器收到這個請求後,好比咱們請求www.xxx.com,它知道你這個域名是.com頂級域名下的,就返回負責.com域名的TLD的一般也是13臺的NS記錄和A記錄,根域名服務器不會爲任何請求作遞歸。這步能夠用dig +trace www.xxx.com來查看過程 canvas

這步是從你的本地DNS服務器中查到了13臺根域名服務器的NS記錄和A記錄,,向其中一臺發起請求

這步是本地DNS服務器向其中一臺根域名服務器發起查詢請求,返回的能夠com頂級域名的13個NS記錄和A記錄 而後本地DNS服務器再向comTLD域名服務器發起查詢請求,其實就是去查詢我存儲在TLD中的域名對應的權威域名服務器的A和NS記錄,TLD看到xxx.com就返回負責該域名的權威DNS服務器的NS和A記錄,本地DNS服務器在向該權威域名服務器發起查詢請求,查詢到了www.xxx.com對應的A記錄(若是一個域名對應多個IP地址,會負載均衡後返回一個IP地址 )返回給本都DNS服務器再返回給終端。

TIP:CNAME經常使用於配置CDN,大體過程是將要訪問的域名指向CDN服務器的域名,當咱們解析咱們的域名後獲得一個CNAME,從新發起對CNAME的解析,獲得一個A記錄和一個NS記錄是CDN廠商本身的DNS服務器,一般是一個智能DNS服務器,它會根據你的IP地址智能的返回對應的CDN節點的IP地址,而後返回給本地DNS服務器返回給用戶。後端

三.與目標服務器創建TCP鏈接

瀏覽器拿到IP地址後就是向目標服務器創建TCP鏈接,計算機與計算機要相互通訊,雙方就必須基於相同的方法相同的協議,TCP就是其中一種,TCP提供可靠的字節流服務,爲了更容易傳送大數據把數據分割,並且TCP協議可以確認數據最終是否到達對方。 TCP創建鏈接的過程是三次握手,其實也就是客戶端和服務器的TCP軟件來交換一系列的Ip分組來確認雙方收發消息的能力,首先了解下交換的數據的結構。

  • IP分組:從TCP一端填入的字節會從另外一端以原有的順序傳出來。TCP的數據是經過名爲IP分組的小數據塊發送來的,HTTP要傳送一條報文時,會以流的形式將報文數據的內容經過一條打開的TCP鏈接按序傳輸,TCP收到http報文數據流後,會將數據流分紅一段段的小數據塊並封裝在IP分組中,每一個IP分組的結構爲一個IP分組首部,一個TCP段首部,一個TCP數據塊
    TCP段首部中FIN,ACK,SYN表示報文標識位,當值爲1的時候有意義
  • SYN:表示該數據塊爲SYN報文在創建TCP鏈接的時候使用
  • ACK:表示確認序列號ack有意義
  • FIN:表示沒有數據要發送了,在關閉報文時候使用
  • TCP段序號(seq):該TCP段的第一個字節序列號,序列號是按順序給發送數據的每個字節都標上號碼編號,序列號的初始值並不是爲0,而是隨機生成的數,後面的字節每個字節加1。
  • 捎帶的確認(ack):確認序列號,代表本身下一步應該接收的序列號,也就是期待IP分組的序列號,這個序列號是根據接收到的IP分組的首部中的序列號(seq)和TCP數據塊中的數據字節長度計算出來的,是根據最後一個字節的序列號加+1,若是要是三次握手階段前兩次握手傳遞的IP分組是沒有TCP數據塊的也就是TCP數據塊是0個字節,這兩次傳遞的ACK就至關於seq+1,首先要理解一個邏輯就是TCP再傳送數據包的時候也就是IP分組承載的TCP數據段發送給對方以後須要接到對方的確認應答(ACK),若是必定時間內沒有確認應答則發生了丟包,會進行重發。之因此說前兩次握手不帶TCP數據段是由於現代的TCP棧都容許在第三次握手的時候發送數據。還要注意的是TCP的數據塊長度沒有寫入IP分組中,實際中是靠IP首部中的數據包長度-IP首部長度-TCP首部長度獲得。如圖

三次握手過程

爲何要進行三次握手: 爲了確認雙方接收與發送能力是否正常 第一次: 服務端收到,服務端能夠確認客戶端發送能力正常,服務器接收能力正常 第二次:客戶端收到,客戶端能夠確認,服務端接收發送能力正常,客戶端接收發送能力正常 第三次:服務器收到,服務器能夠確認客戶端接收消息能力正常。

  • 客戶端向服務器發送一個IP分組,包含SYN標誌位,說明是一個請求創建鏈接的報文,seq隨機生成爲k
  • 服務器端接收到包含SYN的報文,迴應一個IP分組包含SYN標誌位代表服務器也要跟客戶端創建鏈接,seq隨機生成b,還包含ACK標誌,ack爲k+1
  • 客戶端收到服務器的包含SYN,ACK的報文回一個包含ACK標誌,ack=b+1,seq=k+1 至此TCP鏈接創建成功能夠傳輸數據。

四次揮手過程

斷開鏈接的過程須要傳遞四次數據,爲何是四次揮手: 當客戶端要關閉鏈接時,服務器端收到了FIN,僅僅表示客戶端不在發送數據了,可是若是這時候服務器還在向客戶端發送正常數據,客戶端還能夠接收,因此先回一個ack告訴客戶端,我知道了,而後等客戶端接收正常數據完畢後在發送FIN說,服務器也要關閉了,因此斷開鏈接時服務器的ack和FIN分開發送

整個過程至少須要來回發送7個數據包才能完成。

滑動窗口

以每一個段爲單位進行一次確認應答,網絡吞吐量較差,爲解決這個問題TCP引入窗口的概念,確認 應答再也不是以每一個分段而是以更大的單位進行確認,在必定範圍內發送一個包後沒必要一直等待確認應答而是繼續發送,窗口大小就是指無需等待確認應答而能夠繼續發送的數據的最大值,窗口中的數據沒必要發送某一段以後等待確認應答而是能夠繼續發送,某段數據在收到確認應答以前必須在緩衝區中保留這份數據,緩衝區(buffer)是臨時存放收發數據的場所計算機中的一塊內存,收到確認應答後就沒必要在重發就能夠在緩存區中清除。收到確認應答後,將窗口移到應答中序列號的位置,這樣能夠順序的將多個段同時發送提升通訊性能,這種機制被稱爲滑動窗口機制。

若是要是滑動窗口發送過程當中段丟失,第一種狀況是數據到達服務器可是確認應答過程當中丟失,這種是不須要在進行重發的,能夠經過下一個確認應答進行確認,由於服務器端必定會按順序返回ACK(也按順序接收),若是收到了第三段的ACK就說明第二段必定發到了服務器只不過回程的過程丟了,沒必要再重發。第二種狀況是發送過程當中段丟失,若是接收端收到應該接收的序號意外的數據,也就是收到的段序號不連續不會將數據丟棄而是保存在緩衝區,會針對當前爲止收到數據返回ACK,好比若是第二段丟失服務器目前只收到了第一段seq爲1,回的ack爲1001期待下一段的數據seq爲1001,可是第二段數據丟失,服務器收到第三段的seq爲2001,會把第三段放到緩衝區,回第一段數據的ACK期待下一段數據seq爲1001。當發收端連續三次接收到同一個確認應答會對此包進行重發。若是從新收到發送端發送的段,接收端會迴應一個緩衝區中最新段的ACK。

四.SSL握手

TCP鏈接創建成功後,能夠開始傳輸HTTP報文,可是要是HTTPS協議的話就要先進行SSL握手,而後通訊受SSL保護,而後開始發送HTTP請求。HTTPS並非應用層的新協議能夠理解成身披SSL協議外殼的HTTP。先說下爲何要用HTTPS通訊,由於HTTP協議的缺點:

  • 傳輸數據使用明文,沒有加密,容易被竊聽: 好比傳輸報文的時候沒有對請求和響應內容進行加密,經過抓包工具就能抓到傳輸的內容
  • 沒法證實報文完整性,收到的報文可能已被篡改,沒法判斷收到的信息是否準確
  • 沒有驗證通訊方的身份,有可能遭遇假裝 因此HTTPS=HTTP+加密+認證+完整性保護。

加密算法

  • 對稱密鑰加密 是指加密解密使用同一個密鑰的加密方式,這種方式加密時必須將密鑰也發送給對方,可是怎樣能安全的傳輸密鑰是個問題,若是通訊被監聽密鑰也會暴露,加密就沒有意義,並且能夠這麼想,若是密鑰可以安全送達數據也就能夠安全送達就不必加密了。
  • 非對稱加密 發送一方使用對方的公開密鑰進行加密,公開密鑰能夠隨意發佈,對方收到加密信息後再使用私有密鑰進行解密,私有密鑰不能讓其餘人知道。非對稱加密也有問題,那就是發送方使用對方的公鑰也是要傳送過來的,若是傳送過來的公鑰被替換了也沒法證實收到的公鑰是對方發送的公鑰。因此要使用數字證書認證機構(CA)頒發的公開密鑰證書。先要向CA申請證書,提供給CA本身的公鑰,而後CA會對公鑰作數字簽名,而後把公鑰和數字簽名綁定在一塊兒爲數字證書。數字證書=數字簽名+公鑰信息。數字簽名=對公鑰信息進行hash而後再對hash進行私鑰加密。

HTTPS

HTTPS採用的是混合加密機制,在交換密鑰環節使用非對稱加密,交換報文階段使用對稱加密。由於非對稱加密更復雜,因此在交換報文階段使用非對稱加密效率會比較低。也就是說用非對稱加密的公鑰對對稱加密的密鑰進行加密。而後用對稱密鑰的密鑰進行加密報文。交換公鑰的過程如圖:

第三步驗證數字簽名的過程是用一樣的hash算法對公鑰信息進行生成hash和用埋在瀏覽器中的公鑰對數字簽名進行解密的獲得的hash進行對比,相同則驗證經過。這樣就能夠確保拿到的公鑰是沒被篡改的服務器的公鑰。下面總體看下https通訊的步驟也就是ssl握手的步驟,此步驟發生在TCP創建鏈接以後,HTTP報文傳送以前。

  • 客戶端發送報文開始SSL通訊
  • 服務器可進行SSL通訊迴應響應
  • 服務器發送公鑰證書
  • 客戶端驗證證書,並用證書中的公鑰對對稱加密的密鑰進行加密發送給服務器,而後服務器用非對稱加密的私鑰對加密的對稱加密密鑰解密,以後獲得的報文或者發送的報文都用對稱加密密鑰加解密,客戶端也是用對稱加密的密鑰對收發消息進行加解密。
  • 交換報文完畢SSL鏈接創建完成,通訊收到SSL保護,而後開始應用層的HTTP通訊。

發送HTTP請求接收HTTP響應

TCP鏈接創建完成,開始發送HTTP請求,繼續傳輸IP分組。HTTP協議規定,請求從客戶端發出,服務器端響應該請求並返回。

HTTP報文分爲請求報文和響應報文。HTTP報文自己是由多行數據構成的字符串文本。

  • 請求報文:包括請求行,請求頭,請求實體。請求行包括方法,URI,協議版本
  • 響應報文:包括響應行,響應頭,響應主體積。響應行包括,協議版本,狀態碼,緣由短句

狀態碼:描述請求的處理結果,三位數字組成,第一位指定了響應類別

  • 1XX: 信息性狀態碼 接收的請求正在處理
  • 2xx: 成功狀態碼 請求正常處理完畢
  • 3xx: 重定向狀態碼 須要執行附加操做完成請求
  • 4xx: 客戶端錯誤 服務器沒法處理請求
  • 5xx: 服務器錯誤 服務器處理請求出錯

報文首部:首部內容爲客戶端和服務器分別處理內容提供所須要的信息

服務器接收請求並處理而後返回內容進行HTTP響應。

瀏覽器進行渲染顯示頁面

瀏覽器收到服務器的HTTP響應後,Browser主進程將資源經過RenderHost接口交給Renderer進程,GUI渲染線程接管,html解析器拿到字節流以後通過解碼以後是字符流(轉換爲文件指定編碼的字符串),而後詞法分析成有意義的代碼塊也就是詞法單元token,語法分析器構建節點,節點組成一顆DOM樹。

  • 詞法分析: 詞法分析能夠理解爲一個狀態機,輸入字符串根據特定的規則轉換成咱們能理解的token,至關於輸入字符串循環調用nextTkoen函數,每次輸出一個token並且還會標記字符串代表哪些字符已經被處理了。
  • 語法分析: 會關聯一個document對象做爲根節點,借用了棧結構,由於tag標記是有結束和開始標記的,若是token是一個開始標記,建立一個元素添加到DOM TREE中,並壓入還未遇到結束標記的開始棧中。
  • 構建DOM樹:詞法分析後,構建DOM樹節點的時候,也就是從上到下解釋html的時候,若是遇到了script標記,會與Browser進程通訊去請求下載js資源,拿到資源後編譯並執行,這個過程當中若是script標籤沒有async或者defer標記就是同步加載資源,會阻塞後面的資源下載,htm解析生成DOM樹節點也會阻塞,由於js能夠操做DOM,若是遇到csslink標記css資源會異步加載(圖片加載也是),加載完成後會用css解析器解析,此時不會影響html解析也就是DOM樹的建立,由於是兩顆獨立的樹互不相應,可是會影響後續RenderObject渲染樹的構建,由於RenderObject須要用到css的信息,同時會暫停js的執行,由於js也能夠修改css。能夠理解爲css的解析和DOM樹的構建能夠同時進行。
  • 生成佈局渲染樹RenderObject:css通過詞法分析語法分析生成一個CSSStylesheet對象,css匹配html的過程是逆向匹配的過程,再CSSOMRTREE和DOMTREE構建完畢後,纔會生成RenderObject Tree,會爲DOM樹上的每個可視化節點建立一個RenderObject對象而後組成一顆RenderObject樹。
  • RenderLayer樹:咱們的頁面是分層的,在RenderObject建立的同時具備相同座標空間的RenderObject屬於同一個RenderLayer層,document,html,canvas,video等都會建立單獨的層
  • 佈局:每一個RenderObject對象保存了樣式佈局信息,可是還須要從新計算位置和大小進行佈局,由於某些屬性信息,好比margin:0 auto須要轉換成實際的大小才能繪製,先計算子節點再計算父節點,有的父節點高度是靠子節點撐起來的。
  • 繪製:RenderObject會調用繪圖上下文繪製內容,cpu繪製屬於軟件渲染,gpu繪製屬於硬件渲染。軟件渲染繪製的結果是一個位圖bitmap,繪製每一層的時候都用這個位圖,只不過繪製的位置不同,這個位圖實際上就是cpu使用的一塊內存空間,再把這個位圖交給Browser進程進行顯示。webkit的軟件渲染過程是在renderer進程中,網頁的顯示是在Browser進程中進行的。硬件渲染是每一個層都有本身的繪製區域,會有本身的後端存儲(位圖)來保存繪圖結果,繪製到本身的後端存儲而不是整個網頁共享的位圖中,最後將這些層的內容合併到一個圖像中稱爲合成,GPU進程最終繪製的結果再也不像軟件渲染那樣經過共享內存傳遞給Browser進程,而是直接將頁面內容繪製在瀏覽器上。
  • 重排重繪:當觸發重排重繪時,要經歷三個階段,計算佈局,繪製,合成三個階段

tip1:緩存

當瀏覽器去請求資源文件的時候中間還有驗證文件是否過時是否從瀏覽器中讀強緩存或者協商緩存的步驟:當請求資源文件的時候好比請求xx.js或者xx.css。首先在瀏覽器中的緩存中查找一下文件名,如今的資源文件通常都是經過webpack打包生成帶版本號的,瀏覽器的緩存至關於一個hashMap,資源名字當作key,value是當時返回的響應頭和資源的內容。首先找一下若是名字不在緩存中的話直接再去服務器從新請求。 若是文件名字存在於緩存中 的話。還分爲兩種狀況,強緩存和協商緩存。 步驟爲: 先查看對應資源響應頭的expires或者cache-control:max-age +date與當前時間進行對好比果大於當前時間則表示沒過時,則直接使用瀏覽器的緩存,這就是強緩存。若是要是過時了,則會在發起一次請求,拿到緩存中的響應頭中的lastModified和E-tag字段放在此次請求的請求頭中對應放到if-modified-since和if-none-match字段中,若是同時存在的話以e-tag爲準,e-tag通常是資源的md5值或者hash的幾位能夠拿去和服務器上的做對比,lastModified表示上次更改時間與服務器文件時間對比一下,同樣的話表示沒過時。對比後若是要是沒過時,服務器返回304 not-modified 在從瀏覽器中拿到緩存資源,這就是協商緩存,若是過時了則返回新的資源。 瀏覽器緩存有兩個來源,from disk cache磁盤緩存,from memeory cache內存緩存,大概理解爲。開了一次瀏覽器訪問過一次頁面,不關瀏覽器,在請求一次就是from memory cache,關掉了,在請求一次就是from disk cache.

tip2:js相關及執行機制

js引擎會對源代碼進行詞法分析,語法分析,代碼生成而後解釋執行,代碼生成的步驟會進行變量提高分號補全。也可能會在詞法分析生成AST後轉成中間表示也就是字節碼,而後經過JIT技術轉成本地代碼(彙編代碼)被CPU直接執行,或者直接將AST生成本地代碼。

js執行機制

js代碼分爲同步任務和異步任務,全部的同步任務都都在主線程掌管的執行棧中執行,事件觸發線程掌管着一個任務隊列,宏任務包括總體js代碼,事件回調,xhr回調,定時器,UI Render,微任務包括promise回調。首先全局代碼壓入執行棧執行,遇到setTimeout或者xhr或者事件觸發的時候,交給事件觸發線程處理,好比當定時器的時間到時後(由定時器線程進行計數)將事件以及它的回調放進任務隊列中等待執行棧空閒再拿到執行棧中執行。遇到微任務好比當Promise的回調觸發時放入微任務隊列中。當執行棧中的代碼執行完畢後。會去處理微任務隊列中的任務,並且會執行完微任務隊列中的全部任務。接下來會進行UI渲染工做(有可能作,瀏覽器本身決定).此時一次eventLoop完成,進行下一次eventLoop,去任務隊列中取出待執行任務放到執行棧中執行。過程會不斷循環因此叫eventLoop。UI渲染的時機在一次eventLoop的最後,瀏覽器有本身的優化策略不是每輪時間循環都會進行UI渲染,可是UI渲染重繪以前必定會調用requestAnimationFrame的回調。

相關文章
相關標籤/搜索