09.18 BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

作者在若干年前面試騰訊前端崗位的時候,有一個壓軸的題目:在瀏覽器輸入 URL 回車之後發生了什麼?作者當時作為畢業兩年的的切圖仔,當時一臉懵逼,掛的徹底!

下面的答案是作者在網絡上看到的,偏前端層面答案,可供大家參考和收藏

注意:本文的步驟是建立在,請求的是一個簡單的 HTTP 請求,沒有 HTTPS、HTTP2、最簡單的 DNS、沒有代理、並且服務器沒有任何問題的基礎上,儘管這是不切實際的。

大致流程

  • URL 解析
  • DNS 查詢
  • TCP 連接
  • 處理請求
  • 接受響應
  • 渲染頁面

一、URL 解析

地址解析:

首先判斷你輸入的是一個合法的 URL 還是一個待搜索的關鍵詞,並且根據你輸入的內容進行自動完成、字符編碼等操作。

HSTS

由於安全隱患,會使用 HSTS 強制客戶端使用 HTTPS 訪問頁面。

其他操作

瀏覽器還會進行一些額外的操作,比如安全檢查、訪問限制(之前國產瀏覽器限制 996.icu)。

檢查緩存

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

二、DNS 查詢

基本步驟

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

1.瀏覽器緩存

瀏覽器會先檢查是否在緩存中,沒有則調用系統庫函數進行查詢。

2. 操作系統緩存

操作系統也有自己的 DNS緩存,但在這之前,會向檢查域名是否存在本地的 Hosts 文件裡,沒有則向 DNS 服務器發送查詢請求。

3. 路由器緩存

路由器也有自己的緩存。

4. ISP DNS 緩存

ISP DNS 就是在客戶端電腦上設置的首選 DNS 服務器,它們在大多數情況下都會有緩存。

根域名服務器查詢

在前面所有步驟沒有緩存的情況下,本地 DNS 服務器會將請求轉發到互聯網上的根域,下面這個圖很好的詮釋了整個流程:

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

需要注意的點

  1. 遞歸方式:一路查下去中間不返回,得到最終結果才返回信息(瀏覽器到本地DNS服務器的過程)
  2. 迭代方式,就是本地DNS服務器到根域名服務器查詢的方式。
  3. 什麼是 DNS 劫持
  4. 前端 dns-prefetch 優化

三、TCP 連接

TCP/IP 分為四層,在發送數據時,每層都要對數據進行封裝:

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

1. 應用層:發送 HTTP 請求

在前面的步驟我們已經得到服務器的 IP 地址,瀏覽器會開始構造一個 HTTP 報文,其中包括:

  • 請求報頭(Request Header):請求方法、目標地址、遵循的協議等等
  • 請求主體(其他參數)

其中需要注意的點:

  • 瀏覽器只能發送 GET、POST 方法,而打開網頁使用的是 GET 方法

2. 傳輸層:TCP 傳輸報文

傳輸層會發起一條到達服務器的 TCP 連接,為了方便傳輸,會對數據進行分割(以報文段為單位),並標記編號,方便服務器接受時能夠準確地還原報文信息。

在建立連接前,會先進行 TCP 三次握手。

關於 TCP/IP 三次握手,網上已經有很多段子和圖片生動地描述了。相關知識點:

  • SYN 泛洪攻擊

3. 網絡層:IP協議查詢Mac地址

將數據段打包,並加入源及目標的IP地址,並且負責尋找傳輸路線。

判斷目標地址是否與當前地址處於同一網絡中,是的話直接根據 Mac 地址發送,否則使用路由表查找下一跳地址,以及使用 ARP 協議查詢它的 Mac 地址。

注意:在 OSI 參考模型中 ARP 協議位於鏈路層,但在 TCP/IP 中,它位於網絡層。

4. 鏈路層:以太網協議

以太網協議

根據以太網協議將數據分為以“幀”為單位的數據包,每一幀分為兩個部分:

  • 標頭:數據包的發送者、接受者、數據類型
  • 數據:數據包具體內容

Mac 地址

以太網規定了連入網絡的所有設備都必須具備“網卡”接口,數據包都是從一塊網卡傳遞到另一塊網卡,網卡的地址就是 Mac 地址。每一個 Mac 地址都是獨一無二的,具備了一對一的能力。

廣播

發送數據的方法很原始,直接把數據通過 ARP 協議,向本網絡的所有機器發送,接收方根據標頭信息與自身 Mac 地址比較,一致就接受,否則丟棄。

注意:接收方回應是單播。

相關知識點:

  • ARP 攻擊

服務器接受請求

接受過程就是把以上步驟逆轉過來,參見上圖。

四、服務器處理請求

大致流程

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

HTTPD

最常見的 HTTPD 有 Linux 上常用的 Apache 和 Nginx,以及 Windows 上的 IIS。

它會監聽得到的請求,然後開啟一個子進程去處理這個請求。

處理請求

接受 TCP 報文後,會對連接進行處理,對HTTP協議進行解析(請求方法、域名、路徑等),並且進行一些驗證:

  • 驗證是否配置虛擬主機
  • 驗證虛擬主機是否接受此方法
  • 驗證該用戶可以使用該方法(根據 IP 地址、身份信息等)

重定向

假如服務器配置了 HTTP 重定向,就會返回一個 301永久重定向響應,瀏覽器就會根據響應,重新發送 HTTP 請求(重新執行上面的過程)。

URL 重寫

然後會查看 URL 重寫規則,如果請求的文件是真實存在的,比如圖片、html、css、js文件等,則會直接把這個文件返回。

否則服務器會按照規則把請求重寫到 一個 REST 風格的 URL 上。

然後根據動態語言的腳本,來決定調用什麼類型的動態文件解釋器來處理這個請求。

以 PHP 語言的 MVC 框架舉例,它首先會初始化一些環境的參數,根據 URL 由上到下地去匹配路由,然後讓路由所定義的方法去處理請求。

五、瀏覽器接受響應

瀏覽器接收到來自服務器的響應資源後,會對資源進行分析。

首先查看 Response header,根據不同狀態碼做不同的事(比如上面提到的重定向)。

如果響應資源進行了壓縮(比如 gzip),還需要進行解壓。

然後,對響應資源做緩存。

接下來,根據響應資源裡的 MIME 類型去解析響應內容(比如 HTML、Image各有不同的解析方式)。

六、渲染頁面

瀏覽器內核

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

不同的瀏覽器內核,渲染過程也不完全相同,但大致流程都差不多。

基本流程

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

1.HTML 解析

首先要知道瀏覽器解析是從上往下一行一行地解析的。

解析的過程可以分為四個步驟:

1. 解碼(encoding)

傳輸回來的其實都是一些二進制字節數據,瀏覽器需要根據文件指定編碼(例如UTF-8)轉換成字符串,也就是HTML 代碼。

2. 預解析(pre-parsing)

預解析做的事情是提前加載資源,減少處理時間,它會識別一些會請求資源的屬性,比如img標籤的src屬性,並將這個請求加到請求隊列中。

3. 符號化(Tokenization)

符號化是詞法分析的過程,將輸入解析成符號,HTML 符號包括,開始標籤、結束標籤、屬性名和屬性值。

它通過一個狀態機去識別符號的狀態,比如遇到狀態都會產生變化。

4. 構建樹(tree construction)

注意:符號化和構建樹是並行操作的,也就是說只要解析到一個開始標籤,就會創建一個 DOM 節點。

在上一步符號化中,解析器獲得這些標記,然後以合適的方法創建DOM對象並把這些符號插入到DOM對象中。

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

BAT高頻面試題:瀏覽器輸入 URL 回車之後發生了什麼?

瀏覽器容錯進制

你從來沒有在瀏覽器看過類似”語法無效”的錯誤,這是因為瀏覽器去糾正錯誤的語法,然後繼續工作。

事件

當整個解析的過程完成以後,瀏覽器會通過DOMContentLoaded事件來通知DOM解析完成。

2. CSS 解析

一旦瀏覽器下載了 CSS,CSS 解析器就會處理它遇到的任何 CSS,根據語法規範解析出所有的 CSS 並進行標記化,然後我們得到一個規則表。

CSS 匹配規則

在匹配一個節點對應的 CSS 規則時,是按照從右到左的順序的,例如:div p { font-size :14px }會先尋找所有的p標籤然後判斷它的父元素是否為div。

所以我們寫 CSS 時,儘量用 id 和 class,千萬不要過度層疊。

3. 渲染樹

其實這就是一個 DOM 樹和 CSS 規則樹合併的過程。

注意:渲染樹會忽略那些不需要渲染的節點,比如設置了display:none的節點。

計算

通過計算讓任何尺寸值都減少到三個可能之一:auto、百分比、px,比如把rem轉化為px。

級聯

瀏覽器需要一種方法來確定哪些樣式才真正需要應用到對應元素,所以它使用一個叫做specificity的公式,這個公式會通過:

  1. 標籤名、class、id
  2. 是否內聯樣式
  3. !important

然後得出一個權重值,取最高的那個。

渲染阻塞

當遇到一個script標籤時,DOM 構建會被暫停,直至腳本完成執行,然後繼續構建 DOM 樹。

但如果 JS 依賴 CSS 樣式,而它還沒有被下載和構建時,瀏覽器就會延遲腳本執行,直至 CSS Rules 被構建。

所有我們知道:

  • CSS 會阻塞 JS 執行
  • JS 會阻塞後面的 DOM 解析

為了避免這種情況,應該以下原則:

  • CSS 資源排在 JavaScript 資源前面
  • JS 放在 HTML 最底部,也就是


分享到:


相關文章: