[譯文]請求一個URL時發生了什麼

weixin_33670713發表於2017-08-27
3401773-f842f609cb49b6ab.jpg
圖片發自簡書App


大概每家網際網路公司在筆試招人時都會出這樣一道題:寫出 從你在瀏覽器中輸入一個URL整個頁面載入完整結束 這個過程發生了哪些事情,答案越詳細越好。我在網上找到一篇不錯的英文部落格說明這一過程,並把它翻譯了下來(有不理解的地方可以檢視原文或留言):


原文連結:URL原文

以下是譯文內容:

作為一個程式設計師,你肯定對 web應用是如何工作的以及像HTTP,HTML,web伺服器,處理請求器等等包括什麼技術有自己獨到的看法。

在這篇文章裡,我們將會深入瞭解訪問一個URL依次會發生什麼。

1.在瀏覽器中輸入一個URL

從這裡開始:

3401773-93dcebee6a742cf7.png
在ie中輸入Facebook.com

2.瀏覽器對這個域名的IP地址進行查詢

3401773-e4fe8d54b2ff7088.png
通過DNS伺服器查詢

第一步是通過DNS找到這個域名的IP地址,DNS查詢的順序如下所示:

    1.瀏覽器快取 — 瀏覽器會快取DNS記錄一段時間。但作業系統不會告訴瀏覽器每條DNS記錄的存活時間,所以瀏覽器會將其快取一個固定的時間(大多瀏覽器會快取記錄2—30分鐘)。

    2.作業系統快取 — 如果瀏覽器快取中沒有所需的快取記錄,瀏覽器會進行一個系統呼叫(Windows中的gethostbyname).作業系統擁有自己的快取。

    3.路由器快取 — (若前兩個快取都沒有所需的記錄),請求會繼續傳送到擁有DNS快取的路由器上。

  4.ISP DNS快取 — 下個搜尋的地方是ISP的DNS伺服器(伺服器裡有快取).

    5.遞迴搜尋 — 若前四個都沒找到,請求接下來會到ISP的DNS伺服器中,進行一個遞迴搜尋。搜尋的順序是從根名稱伺服器 到 .com頂級名稱伺服器(nameserver)再到 Facebook的名稱伺服器。一般情況下,DNS伺服器會快取具有.com名稱的名稱伺服器,因此在根名稱伺服器尋找沒有意義。

下圖為DNS遞迴查詢示意圖:

3401773-e8d760c1d5627bcd.png
DNS遞迴查詢示意圖


使用DNS有個麻煩:像wikipedia.com或者facebook.com這樣的(訪問量極大的)域名似乎只能對映到一個IP地址。幸運的是,有一些方法可以減輕瓶頸:

迴圈DNS(Round-robin DNS)  定義:DNS查詢時返回多個IP地址。例如:Facebook.com實際上對映到4個ip地址(分散訪問壓力)。

負載均衡器(Load-balancer).  這是一種可以監聽特定IP地址 並將 請求轉發到別的伺服器上的硬體,很多主站點都會使用效能很高的負載均衡器。

地理DNS(Geographic DNS). 它根據使用者的地理位置把域名對映到不同的IP地址上來提高擴充性。這個方法使不同的伺服器不必更新共享狀態,非常適合託管靜態內容。

Anycast. 這是一種可以把單個IP地址對映到多個物理伺服器的路由技術。不過這項技術與TCP協議不相容,所以在這樣的情況下使用較少。


大多數DNS伺服器使用Anycast來實現 DNS查詢過程中 的高可用和低延遲。

3.瀏覽器向Web伺服器傳送HTTP請求

3401773-84f43c592d0e3d91.png
GET請求

由於Facebook主頁是動態頁面(動態頁面到期速度非常快),所以它的主頁不會被快取在瀏覽器中。

因此,瀏覽器會把一下請求傳送給Facebook伺服器:

GET http://facebook.com/HTTP/1.1

Accept: application/x-ms-application, image/jpeg, application/xaml+xml,[...]

User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64;[...]

Accept-Encoding: gzip, deflate

Connection: Keep-Alive

Host: facebook.com

Cookie: datr=1265876274-[...]; locale=en_US; lsd=WW[...]; c_user=2101[…]

以下是對這些請求的說明:

GET請求命名URL並做提取:“http://facebook.com/”。瀏覽器驗證自身(User-Agent頭部)並宣告它將要接受什麼型別的響應(Accept和Accept-Encoding頭部的gzip, deflate)。Connection頭部請求保持TCP連線以保證接受更多的請求。

此請求還包括瀏覽器對這個域名儲存的cookies。Cookies是追蹤網站的不同頁面的請求狀態的鍵值對。在這裡,Cookies儲存了已登入使用者的使用者名稱、伺服器分配給使用者的密碼,使用者設定等等。Cookies儲存在本地客戶端的文字中,並隨著每個請求傳送到伺服器端。

有很多工具可以檢視HTTP請求和迴應。我最喜歡的工具是fiddler,也有很多其他工具(如FireBug)可以幫助我們優化一個網站。

除了GET請求,你可能熟悉的另一種請求是POST請求,這種請求通常用於提交表單。GET請求通過URL傳送其引數(例如http://robozzle.com/puzzle.aspx?id=85)。而POST請求通過他頭部下方的請求體傳送其引數。

URL“http://facebook.com/” 尾部的 斜槓(/) 很重要。在前面的情況下(“http://facebook.com/”),瀏覽器可以安全地新增一個斜槓。而像“http://example.com/folderOrFile”這樣的URL,瀏覽器無法在尾部自動新增斜槓,因為瀏覽器不知道folderOrFile是資料夾還是檔案。在這樣的情況下,瀏覽器不會在URL尾部新增“/”。此時伺服器將對請求進行一個重定向,會導致不必要的結果。

4.facebook伺服器對請求進行永久重定向(301)

3401773-fe4180227d99a84c.png
因為URL有問題

以下是Facebook伺服器返回給瀏覽器的響應內容:

HTTP/1.1 301 Moved Permanently

Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,

pre-check=0

Expires: Sat, 01 Jan 2000 00:00:00 GMT

Location:http://www.facebook.com/

P3P: CP="DSP LAW"

Pragma: no-cache

Set-Cookie: made_write_conn=deleted; expires=Thu, 12-Feb-2009 05:09:50 GMT;

path=/; domain=.facebook.com; httponly

Content-Type: text/html; charset=utf-8

X-Cnection: close

Date: Fri, 12 Feb 2010 05:09:51 GMT

Content-Length: 0

伺服器返回一個301永久重定向響應,告訴瀏覽器跳轉到“http://www.facebook.com/”而不是“http://facebook.com/”。

對於為何伺服器堅持重定向而不是響應使用者想檢視的網頁有些有趣的原因:

首先與搜尋引擎排名有關,如果兩個URL指向同一個頁面(如http://www.igoro.com/和http://igoro.com/),搜尋引擎可能會認為這是兩個不同的站點,由於這兩個網站的入站鏈路較少因此排名較低。搜尋引擎理解永久重定向(301),會把兩個來源的入站連結組成為一個排名。

此外,相同內容用多個URL表示不是 快取友好型(cache-friendly)。當一段內容有多個名稱時,可能會在快取中快取多次。

5.瀏覽器進行重定向

3401773-619bd78feea412a6.png
重定向

瀏覽器知道“http://www.facebook.com/”是要訪問的正確的URL後,會發出另一個GET請求。

GET http://www.facebook.com/HTTP/1.1

Accept: application/x-ms-application, image/jpeg, application/xaml+xml,[...]

Accept-Language: en-US

User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64;[...]

Accept-Encoding: gzip, deflate

Connection: Keep-Alive

Cookie: lsd=XW[...]; c_user=21[...]; x-referer=[...]

Host:www.facebook.com

報文內容與上個請求一樣。

6.伺服器處理請求

3401773-a20f3b73714e3230.png
...

伺服器收到GET請求後,進行處理併傳送響應。

這看似一個簡單的任務,但這個過程裡發生了很多有趣的事—這個過程在個人部落格網站上都會發生,更不用說像facebook這樣大規模的擴充網站了。

      Web伺服器軟體

      Web服務軟體(如:IIS,Apache)收到HTTP請求後會決定用哪個處理程式去處理這個請求。處理程式(用ASP.NET,PHP,Ruby等語言寫成)處理請求並生成響應的HTML。

      在最簡單的情況下,請求處理器可以被儲存到一個可以反映URL結構的檔案層次中(如:http://example.com/folder1/page1.aspx的URL儲存在檔案/httpdocs/folder1/page1.aspx中)。你也可以配置伺服器軟體,使得URL可以手動地儲存到處理請求器中,這樣的話,page1.aspx的公共URL可以是http://example.com/folder1/page1

      處理請求器(Request handler)

      處理請求器讀取請求,請求引數和cookies。它可能會讀取並更新儲存在伺服器上的一些資料。然後,請求處理器會生成一個HTML文件。

每個動態站點都面臨著一個有趣的難題:如何儲存資料。較小的站點通常只用一個資料庫儲存它們的資料,但是對於 儲存著大量資料的網站 或 訪問量很大的網站來說,需要多臺機器分割資料庫。分割方法包括:資料分片(基於主鍵把多個資料庫的表進行分割),複製 和 減少使用 一致性的簡化資料庫。

讓資料更新成本變低的一種方法是把一些資料延遲到批處理進行更新。例如:Facebook需要實時更新新聞,而有些如“您可能認識的人”這樣的功能的資料只需要每晚進行更新(這是我的猜測,實際上的更新機制我也不清楚)。批處理更新使一些不太重要的資料進行統一,從而使資料更新更快更簡單。

7.伺服器返回HTML響應內容

3401773-1343bfcef889e172.png

以下是伺服器生成並返回的響應:

HTTP  /1.1 200 OK

Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,

pre-check=0

Expires: Sat, 01 Jan 2000 00:00:00 GMT

P3P: CP="DSP LAW"

Pragma: no-cache

Content-Encoding: gzip

Content-Type: text/html; charset=utf-8

X-Cnection: close

Transfer-Encoding: chunked

Date: Fri, 12 Feb 2010 09:05:55 GMT

2b3

��������T�n�@����[...]

響應內容大小為36kb,但他們大多數被我修剪掉了。

Content-Encoding頭告訴瀏覽器相應內容用gzip演算法進行壓縮。解壓縮後,你將會看到你期望的HTML內容:


3401773-e5ad3653b8043758.png
複製貼上時有問題,這看來是簡書的一個BUG吧; )

除了壓縮,頭部還會指定 是否緩衝頁面,如何快取頁面,設定cookies(這個響應內容中無),私有資訊等。

8.瀏覽器開始渲染HTML

在接收到整個HTML文件前,瀏覽器就會開始渲染站點:

3401773-5ec75b1a859544a1.png
靜態內容

9.瀏覽器傳送嵌入HTML物件的請求

3401773-b74d27b808437807.png

當瀏覽器渲染HTML時,它會注意到需要從其他URL獲取的標籤(tag)。瀏覽器會傳送GET請求來獲取這些檔案。

以下是我訪問facebook需要的幾個URL:

Images

http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif

http://static.ak.fbcdn.net/rsrc.php/zBS5C/hash/7hwy7at6.gif

CSS style sheets

http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css

http://static.ak.fbcdn.net/rsrc.php/zANE1/hash/cvtutcee.css

JavaScript files

http://static.ak.fbcdn.net/rsrc.php/zEMOA/hash/c8yzb6ub.js

http://static.ak.fbcdn.net/rsrc.php/z6R9L/hash/cq2lgbs8.js

上面每個URL都會經歷這個HTML構建時的過程。如瀏覽器在DNS裡查詢域名,向URL傳送請求,重定向等。

靜態檔案(與動態頁面不同)允許瀏覽器快取他們。有些檔案可能會被儲存到快取中而不需要伺服器提供。瀏覽器知道快取一個特定的檔案需要多長時間,因為響應檔案包括一個Expires頭。此外,每個響應可能還包括一個ETag頭部(類似於版本號)—如果瀏覽器看到本地檔案中已經有這個版本的ETag了,就會停止傳輸。

你能猜到這個URL中的“fbcdn.net”代表什麼嗎?一種看法是認為它意思是“Facebook內容傳送網路”。Facebook使用內容傳送網路(CDN)來分發靜態內容—影象,樣式表和JavaScript檔案。因此,這些檔案會被複制傳輸到全球範圍內很多伺服器中。

靜態內容大多佔一個站點的大部分頻寬,而且能夠通過CDN被複制。通常,網站會使用第三方的CDN提供商而不是自己執行CDN。例如,Facebook的靜態檔案就是由全球最大的CDN提供商Akamai的CDN裝置裡執行的。

作為一個演示,當你ping static.ak.fbcdn.net時,你會收到akamai,net伺服器的響應。有趣的是,重複ping這個URL,可能會收到來自不同伺服器的響應,這表明後臺使用了負載均衡(譯者ping了10次都是一個ip)。

10.瀏覽器進一步傳送AJAX請求

3401773-5255964f0b2071f9.png
恭喜你能看到這裡

在Web2.0的時代,在頁面已經渲染完成的情況下客戶端依然可以和伺服器進行通訊。

例如:Facebook chat會持續更新你線上好友列表。要達到這一點,瀏覽器執行的JS指令碼需要向伺服器傳送非同步請求。非同步請求是程式碼構建的GET、POST請求,轉向特殊的URL。在Facebook的例子裡,客戶端傳送一個POST請求到http://www.facebook.com/ajax/chat/buddy_list.php來獲取你線上好友的列表。

這種模式有時被稱為“AJAX”。代表“Asynchronous JavaScript And XML”,伺服器必須用XML的響應格式(沒有特殊的理由)。例如:Facebook返回JavaScript程式碼段來響應非同步請求。

除此之外,fiddler工具可以通過瀏覽器檢視非同步請求。實際上,你不僅可以觀察請求,還可以修改後重新傳送它們,這樣很容易欺騙AJAX請求。

Facebook chat提供了一個AJAX的有趣例子:把資料從伺服器推送到客戶端。由於HTTP協議是一種 請求-響應 協議,chat 伺服器無法推送新資訊到客戶端。相反,客戶端必須每隔一段時間就訪問伺服器看是否有新訊息到達。

長時間輪詢(long polling)是一種減少這些場景中伺服器負載的技術。當伺服器沒有新資訊時,它將不會傳送響應。而且,若接收客戶端的訊息時超時了,伺服器會發現這條請求並返回訊息。

結論

希望這篇文章可以使你更好理解不同網頁(web piece)如何協同工作。

相關文章