[網絡] 在瀏覽器輸入URL回車之后發生了什么


一  前言

  打開瀏覽器從輸入網址到網頁呈現在大家面前,背后到底發生了什么?經歷怎么樣的一個過程?先給大家來張總體流程圖,具體步驟請看下文分解!

  

  從URL輸入到頁面展現

  總體來說分為以下幾個過程:

  (1)URL 解析

  (2)DNS 解析:將域名解析成 IP 地址

  (3)TCP 連接:TCP 三次握手

  (4)發送 HTTP 請求

  (5)服務器處理請求並響應 HTTP 報文

  (6)瀏覽器解析渲染頁面

  (7)斷開連接:TCP 四次揮手

二  URL解析

  URL(Uniform Resource Locator),統一資源定位符,用於定位互聯網上資源,俗稱網址。比如 http://www.w3school.com.cn/html/index.asp,遵守以下的語法規則:

  scheme://host.domain:port/path/filename

  各部分解釋如下:

    scheme - 定義因特網服務的類型。常見的協議有 http、https、ftp、file,其中最常見的類型是 http,而 https 則是進行加密的網絡傳輸。

    host - 定義域主機(http 的默認主機是 www)

    domain - 定義因特網域名,比如 w3school.com.cn

    port - 定義主機上的端口號(http 的默認端口號是 80)

    path - 定義服務器上的路徑(如果省略,則文檔必須位於網站的根目錄中)。

    filename - 定義文檔/資源的名稱

  解析流程如下:

    (1)地址解析:

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

    (2)HSTS

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

    (3)其他操作

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

    (4)檢查緩存

      

 

三  DNS域名解析

  在瀏覽器輸入網址后,首先要經過域名解析,因為瀏覽器並不能直接通過域名找到對應的服務器,而是要通過 IP 地址。大家這里或許會有個疑問----計算機既可以被賦予 IP 地址,也可以被賦予主機名和域名。比如 www.hackr.jp。那怎么不一開始就賦予個 IP 地址?這樣就可以省去解析麻煩。我們先來了解下什么是 IP 地址

1  IP 地址

  IP 地址是指互聯網協議地址,是 IP Address 的縮寫。IP 地址是 IP 協議提供的一種統一的地址格式,它為互聯網上的每一個網絡和每一台主機分配一個邏輯地址,以此來屏蔽物理地址的差異。IP 地址是一個 32 位的二進制數,比如 127.0.0.1 為本機 IP。

  域名就相當於 IP 地址喬裝打扮的偽裝者,帶着一副面具。它的作用就是便於記憶和溝通的一組服務器的地址。用戶通常使用主機名或域名來訪問對方的計算機,而不是直接通過 IP 地址訪問。因為與 IP 地址的一組純數字相比,用字母配合數字的表示形式來指定計算機名更符合人類的記憶習慣。但要讓計算機去理解名稱,相對而言就變得困難了。因為計算機更擅長處理一長串數字。為了解決上述的問題,DNS 服務應運而生。

2  什么是域名解析

  DNS 協議提供通過域名查找 IP 地址,或逆向從 IP 地址反查域名的服務。DNS 是一個網絡服務器,我們的域名解析簡單來說就是在 DNS 上記錄一條信息記錄

  例如 baidu.com 220.114.23.56(服務器外網IP地址)80(服務器端口號)

3  瀏覽器如何通過域名去查詢 URL 對應的 IP 呢

  基本步驟如下:

   

  1. 瀏覽器緩存

    瀏覽器會先檢查是否在緩存中,沒有則調用系統庫函數進行查詢。瀏覽器會按照一定的頻率緩存 DNS 記錄。

  2. 操作系統緩存

    如果瀏覽器緩存中找不到需要的 DNS 記錄,那就去操作系統中找。操作系統也有自己的 DNS緩存,但在這之前,會向檢查域名是否存在本地的 Hosts 文件里,沒有則向 DNS 服務器發送查詢請求。

  3. 路由器緩存

    路由器也有自己的緩存。

  4. ISP DNS 緩存

    ISP 是互聯網服務提供商(Internet Service Provider)的簡稱,ISP 有專門的 DNS 服務器應對 DNS 查詢請求。ISP DNS 就是在客戶端電腦上設置的首選 DNS 服務器,它們在大多數情況下都會有緩存。

  5. 根域名服務器查詢

    ISP 的 DNS 服務器還找不到的話,它就會向根服務器發出請求,進行遞歸查詢(DNS 服務器先問根域名服務器.com 域名服務器的 IP 地址,然后再問.baidu 域名服務器,依次類推)在前面所有步驟沒有緩存的情況下,本地 DNS 服務器會將請求轉發到互聯網上的根域,下面這個圖很好的詮釋了整個流程:

   

4  小結

  瀏覽器通過向 DNS 服務器發送域名,DNS 服務器查詢到與域名相對應的 IP 地址,然后返回給瀏覽器,瀏覽器再將 IP 地址打在協議上,同時請求參數也會在協議搭載,然后一並發送給對應的服務器。接下來介紹向服務器發送 HTTP 請求階段,HTTP 請求分為三個部分:TCP 三次握手、http 請求響應信息、關閉 TCP 連接。

需要注意的點

  1. 遞歸方式:一路查下去中間不返回,得到最終結果才返回信息(瀏覽器到本地DNS服務器的過程)

  2. 迭代方式,就是本地DNS服務器到根域名服務器查詢的方式。

  3. 什么是 DNS 劫持

  4. 前端 dns-prefetch 優化

四  建立連接

  在客戶端發送數據之前需要發起 TCP 三次握手建立與服務端的連接,用以同步客戶端和服務端的序列號和確認號,並交換 TCP 窗口大小信息。所謂三次握手(Three-way Handshake),是指建立一個TCP連接時,需要客戶端和服務器總共發送3個包。

1  TCP三次握手

  

  (1) 第一次握手:建立連接時,客戶端A發送SYN包(SYN=1,同時選擇一個初始序列號 seq=x )到服務器B,並進入SYN_SEND狀態,等待服務器B確認。

  (2) 第二次握手:服務器B收到SYN包,必須確認客戶A的SYN=1,同時自己也發送一個SYN包(SYN=1,確認號是ack=x+1,同時也要為自己初始化一個序列號 seq=y),即SYN+ACK包,此時服務器B進入SYN_RECV狀態。

  (3) 第三次握手:客戶端A收到服務器B的SYN+ACK包,向服務器B發送確認包ACK(ack=y+1,自己的序列號seq=Z),此包發送完畢,客戶端A和服務器B進入ESTABLISHED狀態,完成。

2  SYN攻擊

  在三次握手過程中,服務器發送 SYN+ACK 之后,收到客戶端的ACK之前的TCP連接稱為半連接(half-open connect)。此時服務器處於Syn_RECV狀態。當收到ACK后,服務器轉入ESTABLISHED狀態。

  Syn攻擊就是攻擊客戶端在短時間內偽造大量不存在的IP地址,向服務器不斷地發送syn包,服務器回復確認包,並等待客戶的確認,由於源地址是不存在的,服務器需要不斷的重發直 至超時,這些偽造的SYN包將長時間占用未連接隊列,正常的SYN請求被丟棄,目標系統運行緩慢,嚴重者引起網絡堵塞甚至系統癱瘓。

  Syn攻擊是一個典型的DDOS攻擊。檢測SYN攻擊非常的方便,當你在服務器上看到大量的半連接狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN攻擊。在Linux下可以如下命令檢測是否被Syn攻擊

  netstat -n -p TCP | grep SYN_RECV

  一般較新的TCP/IP協議棧都對這一過程進行修正來防范Syn攻擊,修改tcp協議實現。主要方法有SynAttackProtect保護機制、SYN cookies技術、增加最大半連接和縮短超時時間等。但是不能完全防范syn攻擊。

3  為什么不能用兩次握手進行連接

  答:3次握手完成兩個重要的功能,既要雙方做好發送數據的准備工作(雙方都知道彼此已准備好),也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被發送和確認。  

  如果把三次握手改成僅需要兩次握手,死鎖是可能發生的。如下圖所示,如果計算機Client和Server之間的通信,假定Client給Server發送一個連接請求分組,Server收到了這個分組,並發送了確認應答分組。按照兩次握手的協定,Server認為連接已經成功地建立了,可以開始發送數據分組。可是,Client在Server的應答分組在傳輸中被丟失的情況下,將不知道Server是否已准備好,不知道Server建立什么樣的序列號,Client甚至懷疑Server是否收到自己的連接請求分組。在這種情況下,Client認為連接還未建立成功,將忽略Server發來的任何數據分組,Client只等待連接確認應答分組。而Server在發出的數據分組超時后,重復發送同樣的數據分組。這樣就形成了死鎖

 

  另外三次握手可以防止已失效的連接請求報文段突然又傳到了Server,因而產生錯誤。假定出現一種異常情況,即Client發出的第一個連接請求報文段並沒有丟失,而是在某些網絡結 點長時間滯留了,一直延遲到連接釋放以后的某個時間才到達Server,本來這是一個早已失效的報文段。但Server收到此失效的連接請求報文段后,就誤認為是Client又發出一次 新的連接請求,於是就向Client發出確認報文段,同意建立連接。假定不采用三次握手,那么只要Server發出確認,新的連接就建立了,這樣一直等待Client發來數據,Server的許多資源就這樣白白浪費了。

五  發送HTTP請求

1  請求報文介紹  

TCP 三次握手結束后,開始發送 HTTP 請求報文
  請求報文由請求行(request line)、請求頭(header)、請求體三個部分組成,如下圖所示

 

1. 請求行包含請求方法、URL、協議版本

  請求方法包含 8 種:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。

  URL 即請求地址,由 <協議>://<主機>:<端口>/<路徑>?<參數> 組成

  協議版本即 http 版本號

POST  /chapter17/user.html HTTP/1.1

  以上代碼中“POST”代表請求方法,“/chapter17/user.html”表示 URL,“HTTP/1.1”代表協議和協議的版本。現在比較流行的是 Http1.1 版本

2. 請求頭包含請求的附加信息,由關鍵字/值對組成,每行一對,關鍵字和值用英文冒號“:”分隔。

  請求頭部通知服務器有關於客戶端請求的信息。它包含許多有關的客戶端環境和請求正文的有用信息。其中比如:Host,表示主機名,虛擬主機;Connection,HTTP/1.1 增加的,使用 keepalive,即持久連接,一個連接可以發多個請求;User-Agent,請求發出者,兼容性以及定制化需求。

3. 請求體,可以承載多個請求參數的數據,包含回車符、換行符和請求數據,並不是所有請求都具有請求數據。

name=tom&password=1234&realName=tomson

  上面代碼,承載着 name、password、realName 三個請求參數。

2  請求流程

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

   

1.  應用層:發送 HTTP 請求

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

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

2. 傳輸層:TCP 傳輸報文

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

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

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

  將數據段打包,並加入源及目標的IP地址,並且負責尋找傳輸路線。判斷目標地址是否與當前地址處於同一網絡中,是的話直接根據 Mac 地址發送,否則使用路由表查找下一跳地址,以及使用 ARP 協議查詢它的 Mac 地址。

4. 鏈路層:以太網協議

  以太網協議

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

      標頭:數據包的發送者、接受者、數據類型

      數據:數據包具體內容

  Mac 地址

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

  廣播

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

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

六  服務器處理請求並返回 HTTP 報文

   大致流程如下:

  

1.  服務器

  服務器是網絡環境中的高性能計算機,它偵聽網絡上的其他計算機(客戶機)提交的服務請求,並提供相應的服務,比如網頁服務、文件下載服務、郵件服務、視頻服務。而客戶端主要的功能是瀏覽網頁、看視頻、聽音樂等等,兩者截然不同。 每台服務器上都會安裝處理請求的應用——web server。常見的 web server 產品有 apache、nginx、IIS 或 Lighttpd 等。

  web server 擔任管控的角色,對於不同用戶發送的請求,會結合配置文件,把不同請求委托給服務器上處理相應請求的程序進行處理(例如 CGI 腳本,JSP 腳本,servlets,ASP 腳本,服務器端 JavaScript,或者一些其它的服務器端技術等),然后返回后台程序處理產生的結果作為響應。

   
          服務器和客戶端區別.png

2. MVC 后台處理階段

  后台開發現在有很多框架,但大部分都還是按照 MVC 設計模式進行搭建的。MVC 是一個設計模式,將應用程序分成三個核心部件:模型(model)-- 視圖(view)--控制器(controller),它們各自處理自己的任務,實現輸入、處理和輸出的分離。

  簡而言之,首先瀏覽器發送過來的請求先經過控制器,控制器進行邏輯處理和請求分發,接着會調用模型,這一階段模型會獲取 redis db 以及 MySQL 的數據,獲取數據后將渲染好的頁面,響應信息會以響應報文的形式返回給客戶端,最后瀏覽器通過渲染引擎將網頁呈現在用戶面前。

3. HTTP響應報文

  響應報文由響應行(request line)、響應頭部(header)、響應主體三個部分組成。如下圖所示:

   

  (1) 響應行包含:協議版本,狀態碼,狀態碼描述

    狀態碼規則如下:
      1xx:指示信息--表示請求已接收,繼續處理。

      2xx:成功--表示請求已被成功接收、理解、接受。

      3xx:重定向--要完成請求必須進行更進一步的操作。

      4xx:客戶端錯誤--請求有語法錯誤或請求無法實現。

      5xx:服務器端錯誤--服務器未能實現合法的請求。

  (2) 響應頭部包含響應報文的附加信息,由 名/值 對組成

  (3) 響應主體包含回車符、換行符和響應返回數據,並不是所有響應報文都有響應數據

七  瀏覽器解析渲染頁面

  瀏覽器拿到響應文本 HTML 后,接下來介紹下瀏覽器渲染機制

  

  瀏覽器解析渲染頁面分為一下五個步驟:

    根據 HTML 解析出 DOM 樹

    根據 CSS 解析生成 CSS 規則樹

    結合 DOM 樹和 CSS 規則樹,生成渲染樹

    根據渲染樹計算每一個節點的信息

    根據計算好的信息繪制頁面

1  根據 HTML 解析 DOM 樹

  根據 HTML 的內容,將標簽按照結構解析成為 DOM 樹,DOM 樹解析的過程是一個深度優先遍歷。即先構建當前節點的所有子節點,再構建下一個兄弟節點。

  在讀取 HTML 文檔,構建 DOM 樹的過程中,若遇到 script 標簽,則 DOM 樹的構建會暫停,直至腳本執行完畢。

2  根據 CSS 解析生成 CSS 規則樹

  解析 CSS 規則樹時 js 執行將暫停,直至 CSS 規則樹就緒。

  瀏覽器在 CSS 規則樹生成之前不會進行渲染。

3  結合 DOM 樹和 CSS 規則樹,生成渲染樹

  DOM 樹和 CSS 規則樹全部准備好了以后,瀏覽器才會開始構建渲染樹。

  精簡 CSS 並可以加快 CSS 規則樹的構建,從而加快頁面相應速度。

4  根據渲染樹計算每一個節點的信息(布局)

  布局:通過渲染樹中渲染對象的信息,計算出每一個渲染對象的位置和尺寸

  回流:在布局完成后,發現了某個部分發生了變化影響了布局,那就需要倒回去重新渲染。

5  根據計算好的信息繪制頁面

  繪制階段,系統會遍歷呈現樹,並調用呈現器的“paint”方法,將呈現器的內容顯示在屏幕上。

  重繪:某個元素的背景顏色,文字顏色等,不影響元素周圍或內部布局的屬性,將只會引起瀏覽器的重繪。

  回流:某個元素的尺寸發生了變化,則需重新計算渲染樹,重新渲染。

八  斷開連接

1  四次揮手

  當數據傳送完畢,需要斷開 tcp 連接,此時發起 tcp 四次揮手。TCP的連接的拆除需要發送四個包,因此稱為四次揮手(four-way handshake)。客戶端或服務器均可主動發起揮手動作,在socket編程中,任何一方執行close()操作即可產生揮手操作。

  

  (1)客戶端A發送一個FIN,用來關閉客戶A到服務器B的數據傳送(報文段4)。發起方向被動方發送報文,Fin、Ack、Seq,表示已經沒有數據傳輸了。並進入 FIN_WAIT_1 狀態。(第一次揮手:由瀏覽器發起的,發送給服務器,我請求報文發送完了,你准備關閉吧)

  (2)服務器B收到這個FIN,它發回一個ACK,確認序號為收到的序號加1(報文段5)。和SYN一樣,一個FIN將占用一個序號。被動方發送確認報文,Ack、Seq,表示同意關閉請求。此時主動發起方進入 FIN_WAIT_2 狀態。(第二次揮手:由服務器發起的,告訴瀏覽器,我請求報文接受完了,我准備關閉了,你也准備吧)

  (3)服務器B關閉與客戶端A的連接,發送一個FIN給客戶端A(報文段6)。被動方向發起方發送報文段,Fin、Ack、Seq,請求關閉連接。並進入 LAST_ACK 狀態。(第三次揮手:由服務器發起,告訴瀏覽器,我響應報文發送完了,你准備關閉吧)

  (4)客戶端A發回ACK報文確認,並將確認序號設置為收到序號加1(報文段7)。發起方向被動方發送報文段,Ack、Seq。然后進入等待 TIME_WAIT 狀態。被動方收到發起方的報文段以后關閉連接。發起方等待一定時間2MSL未收到回復,則正常關閉。(第四次揮手:由瀏覽器發起,告訴服務器,我響應報文接受完了,我准備關閉了,你也准備吧)

2  為什么連接的時候是三次握手,關閉的時候卻是四次握手?

  答:因為當Server端收到Client端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。

  只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。

3  為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

  答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最后一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。在Client發送出最后的ACK回復,但該ACK可能丟失。Server如果沒有收到ACK,將不斷重復發送FIN片段。

  所以Client不能立即關閉,它必須確認Server接收到了該ACK。Client會在發送出ACK之后進入到TIME_WAIT狀態。Client會設置一個計時器,等待2MSL的時間。如果在該時間內再次收到FIN,那么Client會重發ACK並再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。

  MSL指一個片段在網絡中最大的存活時間,2MSL就是一個發送和一個回復所需的最大時間。如果直到2MSL,Client都沒有再次收到FIN,那么Client推斷ACK已經被成功接收,則結束TCP連接。

 

參考

  https://www.cnblogs.com/geoffreyone/p/10021290.html

  https://mp.weixin.qq.com/s/aB6vQ0AmE_bmPZnD_5K59Q


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM