URL輸入到頁面加載解析發生了什麼?

最近在進行前端面試方面的一些準備,看了網上許多相關的文章,發現有一個問題始終繞不開: 在瀏覽器中輸入URL到整個頁面顯示在用戶面前時這個過程中到底發生了什麼。仔細思考這個問題,發現確實很深,這個過程涉及到的東西很多。這個問題的回答真的能夠很好的考驗一個web工程師的水平,於是我自問自答一番。

總體來說分爲以下幾個過程:
	DNS解析
	TCP連接
	發送HTTP請求
	服務器處理請求並返回HTTP報文
	瀏覽器解析渲染頁面
	連接結束
	具體過程

DNS解析

DNS解析的過程就是尋找哪臺機器上有你需要資源的過程。當你在瀏覽器中輸入一個地址時,例如www.baidu.com,
其實不	是百度網站真正意義上的地址。互聯網上每一臺計算機的唯一標識是它的IP地址,但是IP地址並不方便記憶。
用戶更喜歡用	方便記憶的網址去尋找互聯網上的其它計算機,也就是上面提到的百度的網址。所以互聯網設計者需要
在用戶的方便性與可	用性方面做一個權衡,這個權衡就是一個網址到IP地址的轉換,這個過程就是DNS解析。實際上充
當了一個翻譯的角色,實現了網址到IP地址的轉換。網址到IP地址轉換的過程是如何進行的?

在這裏插入圖片描述

  上述圖片是查找www.google.com的IP地址過程。首先在本地域名服務器中查詢IP地址,如果沒有找到的情況下,本地
域名服務器會向根域名服務器發送一個請求,如果根域名服務器也不存在該域名時,本地域名會向com頂級域名服務器發
送一個請求,依次類推下去。直到最後本地域名服務器得到google的IP地址並把它緩存到本地,供下次查詢使用。從上
述過程中,可以看出網址的解析是一個從右向左的過程: com -> google.com -> www.google.com。但是你是否
發現少了點什麼,根域名服務器的解析過程呢?事實上,真正的網址是www.google.com.,並不是我多打了一個.,
這個.對應的就是根域名服務器,默認情況下所有的網址的最後一位都是.,既然是默認情況下,爲了方便用戶,通常都會
省略,瀏覽器在請求DNS的時候會自動加上,所有網址真正的解析過程爲: . -> .com -> google.com. -> www.google.com.。

DNS優化

瞭解了DNS的過程,可以爲我們帶來哪些?上文中請求到google的IP地址時,經歷了8個步驟,這個過程中存在多個請求(同時存在UDP和TCP請求,爲什麼有兩種請求方式,請自行查找)。如果每次都經過這麼多步驟,是否太耗時間?如何減少該過程的步驟呢?那就是DNS緩存。

DNS緩存

DNS存在着多級緩存,從離瀏覽器的距離排序的話,有以下幾種: 瀏覽器緩存,系統緩存,路由器緩存,IPS服務器緩存,
根域名服務器緩存,頂級域名服務器緩存,主域名服務器緩存。
在你的chrome瀏覽器中輸入:chrome://dns/,你可以看到chrome瀏覽器的DNS緩存。
系統緩存主要存在/etc/hosts(Linux系統)中:

在這裏插入圖片描述

DNS負載均衡

不知道大家有沒有思考過一個問題: DNS返回的IP地址是否每次都一樣?如果每次都一樣是否說明你請求的資源都位於同一臺
機器上面,那麼這臺機器需要多高的性能和儲存才能滿足億萬請求呢?其實真實的互聯網世界背後存在成千上百臺服務器,
大型的網站甚至更多。但是在用戶的眼中,它需要的只是處理他的請求,哪臺機器處理請求並不重要。DNS可以返回一個合
適的機器的IP給用戶,例如可以根據每臺機器的負載量,該機器離用戶地理位置的距離等等,這種過程就是DNS負載均衡,
又叫做DNS重定向。大家耳熟能詳的CDN(Content Delivery Network)就是利用DNS的重定向技術,DNS服務器會返回一個跟
用戶最接近的點的IP地址給用戶,CDN節點的服務器負責響應用戶的請求,提供所需的內容。在這裏打個免費的廣告,我平
時使用的比較多的是七牛雲的CDN(免費)儲存圖片,作爲我個人博客的圖牀使用。

TCP連接

HTTP協議是使用TCP作爲其傳輸層協議的,當TCP出現瓶頸時,HTTP也會受到影響。但由於TCP優化這一塊我平常接觸的
並不是很多,再加上大學時的計算機網絡的基礎基本上忘完,所以這一部分我也就不在這裏分析了。

HTTPS協議

我不知道把HTTPS放在這個部分是否合適,但是放在這裏好像又說的過去。HTTP報文是包裹在TCP報文中發送的,服務器
端收到TCP報文時會解包提取出HTTP報文。但是這個過程中存在一定的風險,HTTP報文是明文,如果中間被截取的話會存
在一些信息泄露的風險。那麼在進入TCP報文之前對HTTP做一次加密就可以解決這個問題了。HTTPS協議的本質就是HTTP 
+ SSL(or TLS)。在HTTP報文進入TCP報文之前,先使用SSL對HTTP報文進行加密。從網絡的層級結構看它位於HTTP協議
+ 與TCP協議之間。

在這裏插入圖片描述

HTTPS過程

“三次握手”
HTTPS在傳輸數據之前需要客戶端與服務器進行一個握手(TLS/SSL握手),在握手過程中將確立雙方加密傳輸數據的密碼信
息。TLS/SSL使用了非對稱加密,對稱加密以及hash等。具體過程請參考經典的阮一峯先生的博客TLS/SSL握手過程。
HTTPS相比於HTTP,雖然提供了安全保證,但是勢必會帶來一些時間上的損耗,如握手和加密等過程,是否使用HTTPS需
要根據具體情況在安全和性能方面做出權衡。

HTTP請求

其實這部分又可以稱爲前端工程師眼中的HTTP,它主要發生在客戶端。發送HTTP請求的過程就是構建HTTP請求報文並通過TCP協議中發送到服務器指定端口(HTTP協議80/8080, HTTPS協議443)。HTTP請求報文是由三部分組成: 請求行, 請求報頭和請求正文。

請求行
格式如下: Method Request-URL HTTP-VersionCRLF
eg: GET index.html HTTP/1.1
常用的方法有: GET, POST, PUT, DELETE, OPTIONS, HEAD。
TODO:
請求報頭
請求報頭允許客戶端向服務器傳遞請求的附加信息和客戶端自身的信息。PS: 客戶端不一定特指瀏覽器,有時候也可使用Linux下的CURL命令以及HTTP客戶端測試工具等。常見的請求報頭有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。

在這裏插入圖片描述
上圖是使用Chrome開發者工具截取的對百度的HTTP請求以及響應報文,從圖中可以看出,請求報頭中使用了Accept, Accept-Encoding, Accept-Language, Cache-Control, Connection, Cookie等字段。Accept用於指定客戶端用於接受哪些類型的信息,Accept-Encoding與Accept類似,它用於指定接受的編碼方式。Connection設置爲Keep-alive用於告訴客戶端本次HTTP請求結束之後並不需要關閉TCP連接,這樣可以使下次HTTP請求使用相同的TCP通道,節省TCP連接建立的時間。

請求正文
當使用POST, PUT等方法時,通常需要客戶端向服務器傳遞數據。這些數據就儲存在請求正文中。請求包頭中有一些與請求
正文相關的信息,例如: 現在的Web應用通常採用Rest架構,
請求的數據格式一般爲json。這時就需要設置Content-Type: application/json。

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

自然而然這部分對應的就是後端工程師眼中的HTTP。後端從在固定的端口接收到TCP報文開始,這一部分對應於編程語言中
的socket。它會對TCP連接進行處理,對HTTP協議進行解析,並按照報文格式進一步封裝成HTTP Request對象,供上層
使用。這一部分工作一般是由Web服務器去進行,我使用過的Web服務器有Tomcat, Jetty和Netty等等。

HTTP響應報文也是由三部分組成: 狀態碼, 響應報頭和響應報文。
狀態碼

狀態碼是由3位數組成,第一個數字定義了響應的類別,且有五種可能取值:

1xx:指示信息–表示請求已接收,繼續處理。
2xx:成功–表示請求已被成功接收、理解、接受。
3xx:重定向–要完成請求必須進行更進一步的操作。
4xx:客戶端錯誤–請求有語法錯誤或請求無法實現。
5xx:服務器端錯誤–服務器未能實現合法的請求。平時遇到比較常見的狀態碼有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500(分別表示什麼請自行查找)。
TODO:

在這裏插入圖片描述

該圖是本公司對狀態碼的一個總結,繪製而成的status code map,請大家參考。
1,響應報頭
2,常見的響應報頭字段有: Server, Connection…。
3,服務器返回給瀏覽器的文本信息,通常HTML, CSS, JS, 圖片等文件就放在這一部分。
4,瀏覽器解析渲染頁面
5,瀏覽器在收到HTML,CSS,JS文件後,它是如何把頁面呈現到屏幕上的?下圖對應的就是WebKit渲染的過程。
在這裏插入圖片描述

瀏覽器是一個邊解析邊渲染的過程。首先瀏覽器解析HTML文件構建DOM樹,然後解析CSS文件構建渲染樹,等到渲染樹構建完成後,瀏覽器開始佈局渲染樹並將其繪製到屏幕上。這個過程比較複雜,涉及到兩個概念: reflow(迴流)和repain(重繪)。DOM節點中的各個元素都是以盒模型的形式存在,這些都需要瀏覽器去計算其位置和大小等,這個過程稱爲relow;當盒模型的位置,大小以及其他屬性,如顏色,字體,等確定下來之後,瀏覽器便開始繪製內容,這個過程稱爲repain。頁面在首次加載時必然會經歷reflow和repain。reflow和repain過程是非常消耗性能的,尤其是在移動設備上,它會破壞用戶體驗,有時會造成頁面卡頓。所以我們應該儘可能少的減少reflow和repain。
在這裏插入圖片描述

JS的解析是由瀏覽器中的JS解析引擎完成的。**JS是單線程運行**,也就是說,在同一個時間內只能做一件事,所有的
任務都需要排隊,前一個任務結束,後一個任務才能開始。但是又存在某些任務比較耗時,如IO讀寫等,所以需要一種機
制可以先執行排在後面的任務,這就是:同步任務(synchronous)和異步任務(asynchronous)。JS的執行機制就可以
看做是一個主線程加上一個任務隊列(task queue)。同步任務就是放在主線程上執行的任務,異步任務是放在任務隊列
中的任務。所有的同步任務在主線程上執行,形成一個執行棧;異步任務有了運行結果就會在任務隊列中放置一個事件;
腳本運行時先依次運行執行棧,然後會從任務隊列裏提取事件,運行任務隊列中的任務,這個過程是不斷重複的,所以又
叫做事件循環(Event loop)。

瀏覽器在解析過程中,如果遇到請求外部資源時,如圖像,iconfont,JS等。瀏覽器將重複1-6過程下載該資源。請求過程
是異步的,並不會影響HTML文檔進行加載,但是當文檔加載過程中遇到JS文件,HTML文檔會掛起渲染過程,不僅要等到
文檔中JS文件加載完畢還要等待解析執行完畢,纔會繼續HTML的渲染過程。原因是因爲JS有可能修改DOM結構,這就意味
着JS執行完成前,後續所有資源的下載是沒有必要的,這就是JS阻塞後續資源下載的根本原因。CSS文件的加載不影響JS
文件的加載,但是卻影響JS文件的執行。JS代碼執行前瀏覽器必須保證CSS文件已經下載並加載完畢。

Web優化

上面部分主要介紹了一次完整的請求對應的過程,瞭解該過程的目的無非就是爲了Web優化。在談到Web優化之前,我們回
到一個更原始的問題,Web前端的本質是什麼。我的理解是: 將信息快速並友好的展示給用戶並能夠與用戶進行交互。快速的
意思就是在儘可能短的時間內完成頁面的加載,試想一下當你在淘寶購買東西的時候,淘寶頁面加載了10幾秒才顯示出物
品,這個時候你還有心情去購買嗎?怎麼快速的完成頁面的加載呢?優雅的學院派雅虎給出了常用的一些手段,也就是我們
熟悉的雅虎34條軍規。這34軍規實際上就是圍繞請求過程進行的一些優化方式。

如何儘快的加載資源?答案就是能不從網絡中加載的資源就不從網絡中加載,當我們合理使用緩存,將資源放在瀏覽器端,
這是最快的方式。如果資源必須從網絡中加載,則要考慮縮短連接時間,即DNS優化部分;減少響應內容大小,即對內容進行
壓縮。另一方面,如果加載的資源數比較少的話,也可以快速的響應用戶。當資源到達瀏覽器之後,瀏覽器開始進行解析渲
染,瀏覽器中最耗時的部分就是reflow,所以圍繞這一部分就是考慮如何減少reflow的次數。

總結

寫這篇文章真的非常糾結,前前後後斷斷續續寫了兩個星期,因爲涉及到的東西比較多,再加上有些東西記憶的沒有那麼清晰了,所以不好下筆。所涉及到的大部分內容,也基本上是一筆帶過,只是給讀者一個淺顯的認知,當遇到相關的問題時,知道如何去查詢。大家可以當成一篇Web開發的科普類文章去閱讀。
另外在這裏爲公司的產品打個廣告,在Chrome store中搜索DHC,這是一款超級好用的Web客戶端工具,囊括了很多的功能: 報文分析,API測試等等,可謂說是WEB工程師必備工具。

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