面試體會

Timer發表於2018-12-05

HTTP請求全過程,一臉懵逼,可能是沒有睡醒

第一步:輸入地址

當我們開始在瀏覽器中輸入網址的時候,瀏覽器其實就已經在智慧的匹配可能的url 了,他會從歷史記錄,書籤等地方,找到已經輸入的字串可能對應的 url,然後給出智慧提示,讓你可以補全 url 地址。對於 google 的 chrome 的瀏覽器,他甚至會直接從快取中把網頁展示出來,就是說,你還沒有按下 enter,頁面就出來了。

第二步:瀏覽器查詢域名的 IP 地址

1、請求一旦發起,瀏覽器首先要做的事情就是解析這個域名,一般來說,瀏覽器會首先檢視本地硬碟的 hosts 檔案,看看其中有沒有和這個域名對應的規則,如果有的話就直接使用 hosts 檔案裡面的 ip 地址。

2、如果在本地的 hosts 檔案沒有能夠找到對應的 ip 地址,瀏覽器會發出一個 DNS請求到本地 DNS 伺服器 。本地 DNS 伺服器一般都是你的網路接入伺服器商提供,比如中國電信,中國移動。

3、查詢你輸入的網址的 DNS 請求到達本地 DNS 伺服器之後,本地 DNS 伺服器會首先查詢它的快取記錄,如果快取中有此條記錄,就可以直接返回結果,此過程是遞迴的方式進行查詢。如果沒有,本地 DNS 伺服器還要向 DNS 根伺服器進行查詢。

4、根 DNS 伺服器沒有記錄具體的域名和 IP 地址的對應關係,而是告訴本地 DNS 伺服器,你可以到域伺服器上去繼續查詢,並給出域伺服器的地址。這種過程是迭代的過程。

5、本地 DNS 伺服器繼續向域伺服器發出請求,在這個例子中,請求的物件是.com 域伺服器。.com 域伺服器收到請求之後,也不會直接返回域名和 IP 地址的對應關係,而是告訴本地 DNS 伺服器,你的域名的解析伺服器的地址。

6、最後,本地 DNS 伺服器向域名的解析伺服器發出請求,這時就能收到一個域名和IP 地址對應關係,本地 DNS 伺服器不僅要把 IP 地址返回給使用者電腦,還要把這個對應關係儲存在快取中,以備下次別的使用者查詢時,可以直接返回結果,加快網路訪問。

第三步:瀏覽器向 web 伺服器傳送一個 HTTP 請求

拿到域名對應的 IP 地址之後,瀏覽器會以一個隨機埠(1024<埠<65535)向伺服器的 WEB 程式(常用的有 httpd,nginx 等)80 埠發起 TCP 的連線請求 。 這個連線請求到達伺服器端後(這中間通過各種路由裝置,區域網內除外),進入到網路卡,然後是進入到核心的 TCP/IP 協議棧(用於識別該連線請求,解封包,一層一層的剝開),還有可能要經過 Netfilter 防火牆(屬於核心的模組)的過濾,最終到達 WEB 程式,最終建立了 TCP/IP的連線。

建立了 TCP 連線之後,發起一個 http 請求。一個典型的 http request header 一般需要包括請求的方法,例如 GET 或者 POST 等,不常用的還有 PUT 和 DELETE 、HEAD、OPTION 以及 TRACE 方法,一般的瀏覽器只能發起 GET 或者 POST 請求。

客戶端向伺服器發起 http 請求的時候,會有一些請求資訊,請求資訊包含三個部分:

| 請求方法 URI 協議/版本

| 請求頭(Request Header)

| 請求正文:

下面是一個完整的 HTTP 請求例子:

GET/sample.jspHTTP/1.1

Accept:image/gif.image/jpeg,/

Accept-Language:zh-cn

Connection:Keep-Alive

Host:localhost

User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)

Accept-Encoding:gzip,deflate

 

username=jinqiao&password=1234

注意:最後一個請求頭之後是一個空行,傳送回車符和換行符,通知伺服器以下不再有請求頭。

(1)請求的第一行是“方法 URL 議/版本”:GET/sample.jsp HTTP/1.1

(2)請求頭(Request Header)

請求頭包含許多有關的客戶端環境和請求正文的有用資訊。如,請求頭可以宣告瀏覽器所用的語言,請求正文的長度等。

Accept:image/gif.image/jpeg./

Accept-Language:zh-cn

Connection:Keep-Alive

Host:localhost

User-Agent:Mozila/4.0(compatible:MSIE5.01:Windows NT5.0)

Accept-Encoding:gzip,deflate.

(3)請求正文

請求頭和請求正文之間是一個空行,這個行非常重要,它表示請求頭已經結束,接下來

的是請求正文。請求正文中可以包含客戶提交的查詢字串資訊:username=jinqiao&password=1234

第四步:伺服器的永久重定向響應

伺服器給瀏覽器響應一個 301 永久重定向響應,這樣瀏覽器就會訪問“http://www.google.com/” 而非“http://google.com/”。為什麼伺服器一定要重定向而不是直接傳送使用者想看的網頁內容呢?其中一個原因跟搜尋引擎排名有關。如果一個頁面有兩個地址,就像 http://www.yy.com/和http://yy.com/,搜尋引擎會認為它們是兩個網站,結果造成每個搜尋連結都減少從而降低排名。而搜尋引擎知道301 永久重定向是什麼意思,這樣就會把訪問帶 www的和不帶 www的地址歸到同一個網站排名下。還有就是用不同的地址會造成快取友好性變差,當一個頁面有好幾個名字時,它可能會在快取裡出現好幾次。

**擴充套件知識***

1)301 和 302 的區別

301 和 302 狀態碼都表示重定向,就是說瀏覽器在拿到伺服器返回的這個狀態碼後會自動跳轉到一個新的 URL 地址,這個地址可以從響應的 Location 首部中獲取(使用者看到的效果就是他輸入的地址 A 瞬間變成了另一個地址 B)——這是它們的共同點。他們的不同在於。301 表示舊地址 A 的資源已經被永久地移除了(這個資源不可訪問了),搜尋引擎在抓取新內容的同時也將舊的網址交換為重定向之後的網址;

302 表示舊地址 A 的資源還在(仍然可以訪問),這個重定向只是臨時地從舊地址 A跳轉到地址 B,搜尋引擎會抓取新的內容而儲存舊的網址。

2)重定向原因:

(1)網站調整(如改變網頁目錄結構);

(2)網頁被移到一個新地址;

(3)網頁副檔名改變(如應用需要把.php 改成.Html 或.shtml)。這種情況下,如果不做重定向,則使用者收藏夾或搜尋引擎資料庫中舊地址只能讓訪問客戶得到一個 404 頁面錯誤資訊,訪問流量白白喪失;再者某些註冊了多個域名的網站,也需要通過重定向讓訪問這些域名的使用者自動跳轉到主站點等。

3)什麼時候進行 301 或者 302 跳轉呢?

當一個網站或者網頁 24—48 小時內臨時移動到一個新的位置,這時候就要進行 302跳轉,而使用 301 跳轉的場景就是之前的網站因為某種原因需要移除掉,然後要到新的地址訪問,是永久性的。

清晰明確而言:使用 301 跳轉的大概場景如下:

1、域名到期不想續費(或者發現了更適合網站的域名),想換個域名。

2、在搜尋引擎的搜尋結果中出現了不帶 www 的域名,而帶 www 的域名卻沒有收錄,這個時候可以用 301 重定向來告訴搜尋引擎我們目標的域名是哪一個。

3、空間伺服器不穩定,換空間的時候。

**擴充套件知識***

 

第五步:瀏覽器跟蹤重定向地址

現在瀏覽器知道了 "http://www.google.com/"才是要訪問的正確地址,所以它會傳送另一個 http 請求。這裡沒有啥好說的

第六步:伺服器處理請求

經過前面的重重步驟,我們終於將我們的 http 請求傳送到了伺服器這裡,其實前面的重定向已經是到達伺服器了,那麼,伺服器是如何處理我們的請求的呢?後端從在固定的埠接收到 TCP 報文開始,它會對 TCP 連線進行處理,對 HTTP 協議進行解析,並按照報文格式進一步封裝成 HTTP Request 物件,供上層使用。一些大一點的網站會將你的請求到反向代理伺服器中,因為當網站訪問量非常大,網站

越來越慢,一臺伺服器已經不夠用了。於是將同一個應用部署在多臺伺服器上,將大量使用者的請求分配給多臺機器處理。此時,客戶端不是直接通過 HTTP 協議訪問某網站應用伺服器,而是先請求到 Nginx,Nginx 再請求應用伺服器,然後將結果返回給客戶端,這裡 Nginx的作用是反向代理伺服器。同時也帶來了一個好處,其中一臺伺服器萬一掛了,只要還有其他伺服器正常執行,就不會影響使用者使用。

如圖所示:

 

通過 Nginx 的反向代理,我們到達了 web 伺服器,服務端指令碼處理我們的請求,訪問我們的資料庫,獲取需要獲取的內容等等,當然,這個過程涉及很多後端指令碼的複雜操作。

**擴充套件知識***

什麼是反向代理?

客戶端本來可以直接通過 HTTP 協議訪問某網站應用伺服器,網站管理員可以在中間加上一個 Nginx,客戶端請求 Nginx,Nginx 請求應用伺服器,然後將結果返回給客戶端,此時Nginx 就是反向代理伺服器。

**擴充套件知識***

第七步:伺服器返回一個 HTTP 響應

經過前面的 6 個步驟,伺服器收到了我們的請求,也處理我們的請求,到這一步,它會把它的處理結果返回,也就是返回一個 HTPP 響應。

HTTP 響應與 HTTP 請求相似,HTTP 響應也由 3 個部分構成,分別是:

l 狀態行

l 響應頭(Response Header)

l 響應正文

HTTP/1.1 200 OK

Date: Sat, 31 Dec 2005 23:59:59 GMT

Content-Type: text/html;charset=ISO-8859-1

Content-Length: 122

 

<html>

<head>

<title>http</title>

</head>

<body>

<!-- body goes here -->

</body>

</html>

1)狀態行:

狀態行由協議版本、數字形式的狀態程式碼、及相應的狀態描述,各元素之間以空格分隔。

格式: HTTP-Version Status-Code Reason-Phrase CRLF

例如: HTTP/1.1 200 OK \r\n

-- 協議版本:是用 http1.0 還是其他版本

-- 狀態描述:狀態描述給出了關於狀態程式碼的簡短的文字描述。比如狀態程式碼為 200 時的描述為 ok

-- 狀態程式碼:狀態程式碼由三位數字組成,第一個數字定義了響應的類別,且有五種可能取值。如下:

1xx:資訊性狀態碼,表示伺服器已接收了客戶端請求,客戶端可繼續傳送請求。

2xx:成功狀態碼,表示伺服器已成功接收到請求並進行處理。

3xx:重定向狀態碼,表示伺服器要求客戶端重定向。

4xx:客戶端錯誤狀態碼,表示客戶端的請求有非法內容。

5xx:伺服器錯誤狀態碼,表示伺服器未能正常處理客戶端的請求而出現意外錯誤。

2)響應頭:

響應頭部:由關鍵字/值對組成,每行一對,關鍵字和值用英文冒號":"分隔,典型的響應頭有:

 

 

3)響應正文包含著我們需要的一些具體資訊,比如 cookie,html,image,後端返回的請求資料等等。

這裡需要注意,響應正文和響應頭之間有一行空格,表示響應頭的資訊到空格為止,下圖是fiddler 抓到的請求正文,紅色框中的:響應正文:

 

第八步:瀏覽器顯示 HTML

在瀏覽器沒有完整接受全部 HTML 文件時,它就已經開始顯示這個頁面了,瀏覽器是如何把頁面呈現在螢幕上的呢?不同瀏覽器可能解析的過程不太一樣,這裡我們只介紹webkit 的渲染過程,下圖對應的就是WebKit 渲染的過程,這個過程包括:

解析 html 以構建 dom 樹

-> 構建 render 樹

-> 佈局 render 樹

-> 繪製 render 樹

瀏覽器在解析 html 檔案時,會”自上而下“載入,並在載入過程中進行解析渲染。

解析過程中,如果遇到請求外部資源時,如圖片、外鏈的 CSS、iconfont 等,請求過程是非同步的,並不會影響 html 文件進行載入。

解析過程中,瀏覽器首先會解析 HTML 檔案構建 DOM 樹,然後解析 CSS 檔案構建渲染樹,等到渲染樹構建完成後,瀏覽器開始佈局渲染樹並將其繪製到螢幕上。這個過程比較複雜,涉及到兩個概念: reflow(迴流)和 repain(重繪)。

DOM 節點中的各個元素都是以盒模型的形式存在,這些都需要瀏覽器去計算其位置和大小等,這個過程稱為 relow;當盒模型的位置,大小以及其他屬性,如顏色,字型,等確定下來之後,瀏覽器便開始繪製內容,這個過程稱為 repain。

頁面在首次載入時必然會經歷 reflow 和 repain。reflow 和 repain 過程是非常消耗效能的,尤其是在移動裝置上,它會破壞使用者體驗,有時會造成頁面卡頓。所以我們應該儘可能少的減少 reflow 和 repain。

當文件載入過程中遇到 js 檔案,html 文件會掛起渲染(載入解析渲染同步)的執行緒,不僅要等待文件中 js 檔案載入完畢,還要等待解析執行完畢,才可以恢復 html 文件的渲染執行緒。因為 JS 有可能會修改 DOM,最為經典的 document.write,這意味著,在 JS 執行完成前,後續所有資源的下載可能是沒有必要的,這是 js 阻塞後續資源下載的根本原因。所以我明平時的程式碼中,js 是放在 html 文件末尾的。

JS 的解析是由瀏覽器中的 JS 解析引擎完成的,比如谷歌的是 V8。JS 是單執行緒執行,也就是說,在同一個時間內只能做一件事,所有的任務都需要排隊,前一個任務結束,後一個任務才能開始。但是又存在某些任務比較耗時,如 IO 讀寫等,所以需要一種機制可以先執行排在後面的任務,這就是:同步任務(synchronous)和非同步任務(asynchronous)。JS 的執行機制就可以看做是一個主執行緒加上一個任務佇列(task queue)。同步任務就是放在主執行緒上執行的任務,非同步任務是放在任務佇列中的任務。所有的同步任務在主執行緒上執行,形成一個執行棧;非同步任務有了執行結果就會在任務佇列中放置一個事件;指令碼運

行時先依次執行執行棧,然後會從任務佇列裡提取事件,執行任務佇列中的任務,這個過程是不斷重複的,所以又叫做事件迴圈(Event loop)。

 

第九步:瀏覽器傳送請求獲取嵌入在 HTML 中的資源(如圖片、音訊、視訊、CSS、JS 等等)

其實這個步驟可以並列在步驟 8 中,在瀏覽器顯示 HTML 時,它會注意到需要獲取其他地址內容的標籤。這時,瀏覽器會傳送一個獲取請求來重新獲得這些檔案。這些地址都要經歷一個和 HTML 讀取類似的過程。所以瀏覽器會在 DNS 中查詢這些域名,傳送請求,重定向等等...不像動態頁面,靜態檔案會允許瀏覽器對其進行快取。有的檔案可能會不需要與伺服器通訊,而從快取中直接讀取,或者可以放到 CDN 中


作者:una2017
來源:CSDN
原文:https://blog.csdn.net/zhailihua/article/de...
版權宣告:本文為博主原創文章,轉載請附上博文連結!

相關文章