輸入一個URL到底發生了什麼

參考:http://phpmianshi.com/?id=50

  1. DNS解析

  2. TCP連接

  3. 發送http請求

  4. 服務器處理請求

  5. 瀏覽器解析渲染頁面

  6. 連接結束

DNS解析

根域名服務器(root Name server) 是互聯網域名解析系統(DNS)中最高級別的域名服務器,負責返回頂級域的權威域名服務器地址。它們是互聯網基礎設施中的重要部分,因爲所有域名解析操作均離不開它們。由於DNS和某些協議(未分片的用戶數據協議(UDP)數據包在IPv4內的最大有效大小爲512字節)的共同限制,根域名服務器地址的數量唄限制爲13個。

頂級域名(TLD),就是最高層級的域名。簡單說,就是網址的最後一個部分。比如,網址www.phpmianshi.com的頂級域名就是.com。
他們可以分成兩類。一類是一般性頂級域名(gTLD)也可以叫通用頂級域名,比如.com、net、.edu、.org等等,共有700多個。另一類是國別頂級域名(ccTLD),代表不同的國家和地區,比如.cn(中國)、.io(英屬印度洋領地)等,共有300多個。

名稱服務器(Name Server)在互聯網中是指提供域名服務協議的程序或服務器。它可以將"人類可識別"的標識符,映射爲系統內部通常爲數字形式的標識碼。域名系統(DNS)服務器是最著名的名稱服務器:域名是互聯網兩大主要名字空間之一。

DNS解析過程

  1. 檢查瀏覽器緩存中是否緩存過該域名對應的ip地址

  2. 如果在瀏覽器緩存中沒有找到ip,那麼將繼續查找本機系統是否緩存過ip

  3. 向本地域名解析服務發起域名解析的請求

  4. 向根域名解析服務器發起域名解析請求

  5. 根域名服務器返回gTLD(通用頂級域)域名解析服務器地址

  6. 向gTLD服務器發起解析請求

  7. gTLD服務器接收請求並返回Name Server服務器

  8. Name Server 服務器返回ip地址給本地服務器

  9. 本地域名服務器緩存解析結果

  10. 返回解析結果給用戶

DNS負載均衡

DNS負載均衡技術的實現原理是在DNS服務器中爲同一個主機名配置多個IP地址,在應答NDS查詢時,DNS服務器對每個查詢將以DNS文件中主機記錄的IP地址按順序返回不同的解析結果,將客戶端的訪問引導到不同的機器上去,使得不同的客戶端訪問不同的服務器,從而達到負載均衡的目的。

TCP連接

三次握手的目的

目的是爲了防止已經失效的連接請求報文段突然有傳送到了服務端,因而產生錯誤

三次握手的過程

  1. 客戶端發送一個帶SYN=1,Seq=X 的數據包到服務器端(第一次握手,由瀏覽器發起,告訴服務器我要發送請求了)

  2. 服務器發揮一個帶SUN=1,ACK=Y的響應包以示傳達確認信息(第二次握手,由服務器發起,告訴瀏覽器我準備接收了,可以發送了)

  3. 客戶端再傳回一個帶ACK=Y+1,Seq=Z的數據報,代表握手結束(第三次握手,由瀏覽器發送,告訴服務器,我準備發送了)

報文格式:

  1. 序號:Seq序號(Sequence number順序號碼),佔32位,用來標識從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標記。

  2. 確認序號:Ack序號(Acknowledge number確認號碼),佔32位,只有ACK標誌位爲1時,確認序號字段纔有效,Ack=Seq+1。

  3. 標誌位(位碼):共6個,即URG、ACK、PSH、RST、SYN、FIN,具體含義如下:

    • URG:urgent,緊急。緊急指針(urgent pointer)有效。

    • ACK:acknowledgement,確認。確認序號有效。

    • PSH:push,傳送。接收方應該儘快將這個報文交給應用層。

    • RST:reset,重置。重置連接。

    • SYN:synchronous,建立聯機。發起一個新連接。

    • FIN:finish,結束。釋放一個連接。

需要注意的是:

  1. 不要將確認序號Ack與標誌位中的ACK搞混了

  2. 確認方Ack=發起方Seq+1,兩端配對。

我們用大白話解釋下三次握手

快遞小哥:你好,你的快遞到了,你在家沒?
小明:在家呢,送過來吧。
快遞小哥:好的,馬上送到。

發送HTTP請求

請求報文由請求行,請求頭,空行,請求體四個部分組成。

請求行包含請求方法,URL,協議版本

  • 請求方法包括:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。

  • URL即請求地址

  • 協議版本即http版本號

GET /js/count.js HTTP/1.1

上面代碼中GET代表請求方法,/js/count.js表示URL,HTTP/1.1代表http版本

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

請求頭部通知服務器關於客戶端請求的信息。它包含許多有關的客戶端環境和請求正文的有用信息。比如:

  • Host:主機名,虛擬主機

  • Connection:HTTP/1.1增加的,使用keeoalive,即持久連接,一個連接可以發多個請求

  • User-Agent:客戶端程序的信息,就是我發送請求的瀏覽器信息

  • Accept:瀏覽器可以接收的媒體數據類型

  • Accept-Encoding:是瀏覽器用來告知服務器它能夠支持的內容編碼及內容編碼的優先級順序,可一次性指定多種內容編碼

  • Accept-Language:高hi服務器瀏覽器能夠處理的自然語言集

  • Cookie:瀏覽器記錄的用戶相關信息

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

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

響應報文由相響應行、響應頭、響應主體三個部分組成

響應行包含協議版本、狀態碼、狀態碼描述

HTTP/1.1 200 OK
  • 協議版本:HTTP/1.1

  • 狀態碼:200

    • 200:請求成功

    • 201:以創建,成功請求並創建了新的資源

    • 203:非授權信息。請求成功,但返回的meta信息不在原始的服務器,而是一個副本

    • 204:無內容。服務器處理成功,但未返回內容。在未更新網頁的情況下,可確保瀏覽器繼續顯示當前文檔

    • 301:永久重定向

    • 302:臨時重定向

    • 307:臨時重定向。與302類似。使用GET請求重定向

    • 400:客戶端請求的語法錯誤,服務器無法理解(給服務端傳的參數和服務端指定接受的字段不同)

    • 404:服務器無法根據客戶端的請求找到資源

    • 405:客戶端請求中的方法被禁止(請求方法不對,比如服務端設置GET請求,客戶端使用POST請求)

    • 500:服務端內部錯誤

  • 狀態碼描述:ok

響應頭

響應頭爲客戶端提供了額外的信息,使得客戶端可以做出更好的響應。

  • Server:服務器告訴客戶端當前服務器上安裝得HTTP服務應用程序的信息,可能包含服務器上的軟件應用名稱,版本號

  • Content-Type:表明了服務器返回給瀏覽器的實體內容的類型

  • Transfer-Encoding: chunked 表示輸出的長度不能確定,普通的靜態頁面、圖片之類的基本上都用不到這個。動態頁面可能會用到。

  • Cache-Control:緩存控制,默認值爲private,表示內容只緩存到私有緩存中(僅客戶端可以緩存,代理服務器不可緩存)

  • Expires:告知客戶端資源失效日期

響應主體

服務端給客戶端返回的文本信息

瀏覽器解析渲染頁面

瀏覽器從最初接收請求來的HTML、CSS、JS等資源,然後解析,構建樹、渲染布局、繪製,最後呈現給客戶能看到的界面的整個過程

主要包括以下幾步

  1. 解析HTML生成DOM樹

  2. 解析CSS生成CSSOM規則樹

  3. 將DOM樹與CSSOM規則樹合併在一起生成渲染樹

  4. 遍歷渲染樹開始佈局,計算每個節點的位置大小信息

  5. 將渲染樹每個節點繪製到屏幕

構建DOM樹

當瀏覽器接收到服務器響應來的HTML文檔後,會遍歷文檔節點,生成DOM樹。需要注意的是,DOM樹生成過程中可能會被CSS和JS的加載執行阻塞。

構建CSSOM規則書

瀏覽器解析CSS文件並生成CSS規則樹,每個CSS文件都被解析成一個StyleSheet對象,每個對象都包含CSS規則。CSS規則對象包含對應於CSS語法的選擇器和聲明對象以及其他對象

渲染阻塞

當瀏覽器遇到一個script標記時,DOM構建將暫停,直至腳本完成執行,然後繼續構建DOM。每次去執行Js腳本都會嚴重阻塞DOM樹的構建,如果js腳本還操作的CSSOM,而正好這個CSSOM還沒有下載和構建,瀏覽器甚至會延遲腳本執行和構建DOM,直至完成其CSSOM的下載和構建。

所以script標籤的位置很重要。實際使用時,可以遵循下面兩個原則:

  1. CSS優先:引入順序上,CSS資源先於JS資源。

  2. JS置後:通常我們把JS代碼放到頁面底部,且JS應儘量少影響DOM構建

構建渲染樹

通過DOM樹和CSS規則樹我們便可以構建渲染樹。瀏覽器會先從DOM樹的根節點開始遍歷每個可見節點。對每個可見節點,找到其適配的CSS樣式規則並應用。

渲染樹構建完成後,每個節點都是可見節點並且都含有其內容和對應的規則的樣式。這也是渲染樹與DOM樹最大的區別。渲染樹是用於顯示,那些不可見的元素當然就不會在這棵樹中出現了,除此之外,display等於none的也不會被顯示在這棵樹裏頭,但是visibility等於hidden的元素是會顯示在這棵樹裏頭的。

渲染樹佈局

佈局階段會從渲染樹的根節點開始遍歷,然後確定每個接待你對象在頁面上的確切大小與位置,佈局階段的輸出是一個盒子模型,他會精確的捕獲每個元素在屏幕內的確切位置與大小。

渲染樹繪製

在繪製階段,遍歷渲染樹,調用渲染器的paint()方法在屏幕上顯示其內容。渲染樹的繪製工作是由瀏覽器的UI後端組件完成

迴流與重繪

根據選安然樹佈局,計算CSS樣式,即每個節點在頁面中的帶線啊哦和位置等幾何信息。HTML默認是流式佈局的,CSS和JS會打破這種佈局,改變DOM的外觀樣式以及大小和位置。這時就會觸發迴流和重繪

重繪

屏幕的一部分重繪,不影響整體佈局,比如某個CSS的背景色變了,但元素的幾何尺寸和位置不變。

常見引起重回的屬性

  • color

  • border-style

  • box-shadow

  • background

  • background-size

  • border-radius

  • background-position

迴流

當元素的大小位置改變,需要重新驗證並計算渲染樹。是渲染樹的一部分或全部發生了變化。

常見引起迴流的屬性和方法

  • 添加或者刪除可見的DOM元素

  • 元素尺寸改變--邊距、填充、邊框、寬度和高度

  • 內容變化,比如用戶在input中輸入文字

  • 瀏覽器窗口尺寸改變

  • 計算offsetWidth和offsetHeight

從上面可以看出:迴流必將引起重繪,而重繪不一定會引起迴流。

css3硬件加速(GPU加速)

硬件加速會自動規避迴流和重繪
css中有以下幾個屬性能觸發硬件加速

  1. transform

  2. opacity

  3. filter

  4. will-change

如果有一些元素不需要用到上述屬性,但是需要觸發硬件加速效果,可以使用一些小技巧來誘導瀏覽器開啓硬件加速。

    -webkit-transform: translateZ(0);
    -moz-transform: translateZ(0);
    -ms-transform: translateZ(0);
    -o-transform: translateZ(0);    transform: translateZ(0); 
    /**或者**/
    transform: rotateZ(360deg);    transform: translate3d(0, 0, 0);

要注意的問題

  • 過多的開啓硬件加速可能會耗費較多的內存。

  • GPU 渲染會影響字體的抗鋸齒效果。這是因爲 GPU 和 CPU 具有不同的渲染機制,即使最終硬件加速停止了,文本還是會在動畫期間顯示得很模糊。

斷開連接

現在的頁面爲了優化請求的耗時,默認都會開啓持久連接(keep-alive),那麼一個TCP連接確切關閉的時機,是這個tab標籤頁關閉的時候。這個關閉的過程就是四次揮手.由於TCP連接時全雙工的,因此,每個方向都必須要單獨進行關閉,這一原則是當一方完成數據發送任務後,發送一個FIN來終止這一方向的連接,收到一個FIN只是意味着這一方向上沒有數據流動了,即不會再收到數據了,但是在這個TCP連接上仍然能夠發送數據,直到這一方向也發送了FIN。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉

  1. client發送一個FIN,用來關閉client到server的數據傳送,cliient進入FIN_WAIT_1狀態

  2. server收到FIN後,發送一個ack給client,確認序列號爲收到序列號+1(與SYN相同,一個FIN佔用一個序號),server進入CLOSE_WAIT狀態

  3. server發送一個FIN,用來關閉server到client的數據傳送,server進入LAST_ACK狀態

  4. client收到FIN後,client進入TIME_WAIT狀態,接着發送一個ack給server,確認序列號爲收到序列號+1,server進入CLOSED狀態,完成四次揮手

狀態詳解:
  CLOSED:表示初始狀態。


  LISTEN:表示服務器端的某個SOCKET處於監聽狀態,可以接受連接了。


  SYN_RCVD:這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是服務器端的SOCKET在建立TCP連接時的三次握手會話過程中的一箇中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程序,故意將三次TCP握手過程中最後一個ACK報文不予發送。因此這種狀態時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。


  SYN_SENT:這個狀態與SYN_RCVD遙相呼應,當客戶端SOCKET執行CONNECT連接時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。


  ESTABLISHED:表示連接已經建立了。


  FIN_WAIT_1:這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連接,向對方發送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。


  FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點數據需要傳送給你,稍後再關閉連接。


  TIME_WAIT:表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL(Max Segment Lifetime)後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。


  CLOSING:這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你發送FIN報文後,按理來說是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方幾乎在同時close一個SOCKET的話,那麼就出現了雙方同時發送FIN報文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連接。


  CLOSE_WAIT:這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後發送FIN報文給自己,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是查看你是否還有數據發送給對方,如果沒有的話,那麼你也就可以close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。


  LAST_ACK:它是被動關閉一方在發送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章