一個web請求到底發生了什麼?

        HTTP其實就是一個客戶端與服務器之間的一種通訊協議,http客戶端發起請求,就會在服務端建立一個端口,而http服務器就在端口監聽客戶端的請求,HTTP服務器返回狀態和內容。css

1、從輸入一個網址開始

當咱們在瀏覽器輸入一個網址,而後按下回車,接下來瀏覽器顯示了頁面。網速好的話這之間可能就一秒,但在這一秒內到底發生了什麼?前端

本文主要內容是試圖記錄一個完整 Web 請求的詳細過程,從用戶在瀏覽器中輸入 URL 地址提及,而後瀏覽器如何找到服務器地址的過程,併發起請求;分析請求在達反向代理服務器內部處理過程;最後到請求在服務器端處理完成後,瀏覽器渲染響應頁面過程。web

大體過程以下:數據庫

Web請求的工做原理能夠簡單地概括爲:瀏覽器

  1. 瀏覽器經過 DNS 把域名解析成對應的IP地址;
  2. 根據這個 IP 地址在互聯網上找到對應的服務器,創建 Socket 鏈接;
  3. 客戶端向服務器發送HTTP協議請求包,請求服務器裏的資源文檔;
  4. 在服務器端,實際上還有複雜的業務邏輯:服務器可能有多臺,到底指定哪臺服務器處理請求,這須要一個負載均衡設備來平均分配全部用戶的請求;
  5. 還有請求的數據是存儲在分佈式緩存裏仍是一個靜態文件中,或是在數據庫裏;
  6. 當數據返回瀏覽器時,瀏覽器解析數據發現還有一些靜態資源(如:css,js或者圖片)時又會發起另外的請求,而這些請求可能會在CDN上,那麼CDN服務器又會處理這個用戶的請求。
  7. 客戶端與服務器斷開。由客戶端解釋HTML文檔,在客戶端屏幕上渲染圖形結果。

一個 HTTP 事務就是這樣實現的,看起來很簡單,原理實際上是挺負雜的。須要注意的是客戶機與服務器之間的通訊是非持久鏈接的,也就是當服務器發送了應答後就與客戶機斷開鏈接,等待下一次請求。緩存

但須要注意的是,從 HTTP 1.1 開始,服務器能夠與客戶端保持長鏈接,不必定是請求完成後就斷開鏈接,這取決於服務器的操做。安全

2、DNS 域名解析

首先來看看最早發生的事情——DNS 域名解析,簡單的說就是把域名翻譯成 IP 地址。例如:把 www.test.com 這個域名翻譯成對應 IP 192.168.1.1,這裏只是舉個例子。服務器

若是你在瀏覽器中直接輸入的 IP 地址,那麼實際上會跳過這個步驟,不然會經理下面幾部:微信

一、瀏覽器緩存檢查網絡

瀏覽器會首先搜索瀏覽器自身的 DNS 緩存,緩存時間比較短,大概只有1分鐘,且只能容納1000條緩存,看自身的緩存中是否有對應的條目,並且沒有過時,若是有且沒有過時則解析到此結束。

二、操做系統緩存檢查 + hosts 解析

若是瀏覽器的緩存裏沒有找到對應的條目,操做系統也會有一個域名解析的過程,那麼瀏覽器先搜索操做系統的 DNS 緩存中是否有這個域名對應的解析結果,若是找到且沒有過時則中止搜索,解析到此結束。

在 Linux 中能夠經過 /etc/hosts 文件來設置,能夠將任何域名解析到任何可以訪問的 IP 地址。若是在這裏指定了一個域名對應的 IP 地址,那麼瀏覽器會首先使用這個 IP 地址。當解析到這個配置文件中的某個域名時,操做系統會在緩存中緩存這個解析結果,緩存的時間一樣是受這個域名的失效時間和緩存的空間大小控制的。

三、本地區域名服務器(Local DNS Server)解析

若是在 hosts 文件中也沒有找到對應的條目,瀏覽器會發起一個 DNS 的系統調用,會向本地配置的首選 DNS 服務器發起域名解析請求(經過的是 UDP 協議向 DNS 的 53 端口發起請求,這個請求是遞歸的請求,也就是運營商的DNS服務器必須得提供給咱們該域名的IP地址)。

在咱們的網絡配置中都會有「DNS 服務器地址」這一項,這個地址就用於解決前面所說的若是兩個過程沒法解析時要怎麼辦。操做系統會把這個域名發送給這裏設置的 LDNS,也就是本地區的域名服務器。

這個 DNS 一般都提供給你本地互聯網接入的一個 DNS 解析服務,例如你是在學校接入互聯網,那麼你的 DNS 服務器確定在你的學校;若是你是在一個小區接入互聯網的,那這個 DNS 就是提供給你接入互聯網的應用提供商,即電信或者聯通。大約 80% 的域名解析都到這裏就已經完成了,因此 LDNS 主要承擔了域名的解析工做。

四、根域名服務器解析(Root Server)

若是 LDNS 沒有找到對應的條目,則由運營商的 DNS 代咱們的瀏覽器發起迭代 DNS 解析請求。它首先是會找根域的 DNS 的 IP 地址,找到根域的 DNS 地址,就會向其發起請求。而後根域名服務器返回給本地域名服務器一個所查詢域的主域名服務器(gTLD Server)地址。

五、主域名服務器(gTLD Server)

本地域名服務器(LDNS Server)再向上一步返回的 gTLD 服務器發送請求。

接受請求的 gTLD 服務器查找並返回此域名對應的 Name Server 域名服務器的地址,這個 Name Server 一般就是你註冊的域名服務器,例如你在某個域名服務提供商申請的域名,那麼這個域名解析任務就由這個域名提供商的服務器來完成。

Name Server 域名服務器會查詢存儲的域名和IP的映射關係表,正常狀況下都根據域名獲得目標IP記錄,連同一個 TTL 值返回給 DNS Server 域名服務器。

下圖彙總了上面所說的 DNS 解析過程:

3、TCP 的 3 次握手

拿到域名對應的 IP 地址後,User-Agent(通常是指瀏覽器)會以一個隨機端口(1024 < 端口 < 65535)向服務器的 WEB 程序發起 TCP 的鏈接請求。

這裏還涉及 ARP(地址解析協議):是根據 IP 地址獲取物理地址 (MAC 地址) 的一個協議。
當一個數據幀通過屢次路由到達目的網絡時,路由器只能知道其數據幀中的目的 IP 地址,而不知目標主機的硬件地址,網絡層使用的是 IP地址,可是在實際網絡鏈路上傳送數據幀時,最終必須使用該網絡的硬件地址,此時須要目的主機的硬件地址,就要使用 ARP 來獲取到對應 IP 地址主機的物理地址。

這個鏈接請求(原始的 Http 請求通過 TCP/IP 4層模型的層層封包)到達服務器端後(這中間經過各類路由設備,局域網內除外),進入到網卡,而後是進入到內核的 TCP/IP 協議棧(用於識別該鏈接請求,解封包,一層一層的剝開),還有可能要通過Netfilter防火牆(屬於內核的模塊)的過濾,最終到達WEB程序,最終創建了TCP/IP的鏈接。

  1. Client 首先發送一個鏈接試探,SYN = 1 表示這是一個鏈接請求或鏈接接受報文,同時表示這個數據報不能攜帶數據,seq = x 表示 Client 本身的初始序號(seq = 0 就表明這是第 0 號包),這時候 Client 進入 syn_sent 狀態,表示客戶端等待服務器的回覆。

  2. Server 監聽到鏈接請求報文後,如贊成創建鏈接,則向 Client 發送確認。報文中的 SYN 和 ACK 都置 1 ,ACK = x + 1 表示指望收到對方下一個報文段的第一個數據字節序號是 x+1,同時代表 x 爲止的全部數據都已正確收到(ACK = 1 實際上是 ACK = 0 + 1,也就是指望客戶端的第 1 個包),seq = y 表示 Server 本身的初始序號(seq = 0 就表明這是服務器這邊發出的第 0 號包)。這時服務器進入 syn_rcvd,表示服務器已經收到 Client 的鏈接請求,等待確認。

  3. Client 收到確認後還需再次發送確認,同時攜帶要發送給 Server 的數據。ACK 置 1 表示確認號 ack= y + 1 有效(表明指望收到服務器的第 1 個包),Client本身的序號 seq= x + 1(表示這就是個人第1個包,相對於第0個包來講的),一旦收到Client的確認以後,這個TCP鏈接就進入 Established 狀態,就能夠發起請求了。

4、Nginx 反向代理

一、反向代理

反向代理(Reverse Proxy)方式是指:代理服務器來接受 Internet 上的鏈接請求,而後將請求轉發給內部網絡上的服務器,並將從內部網絡上服務器獲得的結果返回給 Internet 上請求鏈接的客戶端。此時代理服務器對外就表現爲一個服務器,反向代理服務器對於客戶端而言它就像是原始服務器,而且客戶端不須要進行任何特別的設置。

反向代理的做用:

  1. 保證內網的安全,可使用反向代理提供 WAF 功能,阻止 web 攻擊。

  2. 負載均衡,經過反向代理服務器來優化網站的負載。

二、正向代理

既然有反向代理,就確定有正向代理。什麼叫正向代理呢?

正向代理(Forward Proxy)一般都被簡稱爲代理,就是在用戶沒法正常訪問外部資源,能夠經過代理的方式,讓用戶繞過防火牆,從而鏈接到目標網絡或者服務。

正向代理的工做原理就像一個跳板。

好比:我訪問不了 google.com,可是我能訪問一個代理服務器 A,A 能訪問 google.com,因而我先連上代理服務器 A,告訴它我須要 google.com 的內容,A 就去取回來,而後返回給我。

從網站的角度,只在代理服務器來取內容的時候有一次記錄,有時候並不知道是用戶的請求,也隱藏了用戶的資料,這取決於代理告不告訴網站。

正向代理是一個位於客戶端和原始服務器(origin server)之間的服務器。爲了從原始服務器取得內容,客戶端向代理髮送一個請求並指定目標(原始服務器),而後代理向原始服務器轉交請求並將得到的內容返回給客戶端。

三、正向代理與反向代理對比

5、關閉 TCP 鏈接

這一步不是全部的網頁都會這麼作,例如網頁版微信就沒有關閉 TCP 鏈接,由於微信上別人能夠隨時發消息給你,實際上別人先把消息發送到了微信服務器,微信服務器再經過 TCP 連接,把消息推送到你的屏幕上。

試想一下,若是網頁版微信關閉了 TCP 鏈接會怎樣?

結果是:你不刷新網頁,就永遠收不到消息了。同時,若是你頻繁的發消息給別人,那麼就在頻繁的建立鏈接,關閉鏈接,這是很消耗資源的。因此微信就乾脆不關閉 TCP 鏈接,這樣微信服務器就能夠給咱們的瀏覽器發消息。

下圖是一次 Http 請求報文頭部信息,其中 Connection: keep-alive 意味着此次請求結束後不會關閉 TCP 鏈接。

固然不是全部的 HTTP 請求都沒有關閉鏈接,例如一篇博文,瀏覽器收到數據顯示就能夠了,沒有那麼多動態數據,我看完就關了,這時就應該關閉 TCP 鏈接,固然這仍是取決於請求的服務器。說了這麼多,還沒說關閉鏈接。

關閉 TCP 鏈接專業點說叫作「四次揮手」,與 TCP 創建鏈接的「三次握手」相對應。

因爲TCP鏈接是全雙工的,所以每一個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個 FIN 來終止這個方向的鏈接。收到一個 FIN 只意味着這一方向上沒有數據流動,一個TCP鏈接在收到一個 FIN 後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另外一方執行被動關閉。


結束語: 作一個努力、勤奮、主動的前端工程師

相關文章
相關標籤/搜索