天天看點

[IT]當你在浏覽器位址欄輸入一個URL後回車,将會發生的事情?

原文:what really happens when you navigate to a url

作為一個軟體開發者,你一定會對網絡應用如何工作有一個完整的階層化的認知,同樣這裡也包括這些應用所用到的技術:像浏覽器,http,html,網絡伺服器,需求處理等等。

本文将更深入的研究當你輸入一個網址的時候,背景到底發生了一件件什麼樣的事。

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?
[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

導航的第一步是通過通路的域名找出其ip位址。

dns查找過程如下:

浏覽器緩存 – 浏覽器會緩存dns記錄一段時間。 有趣的是,作業系統沒有告訴浏覽器儲存dns記錄的時間,這樣不同浏覽器會儲存個自固定的一個時間(2分鐘到30分鐘不等)。

系統緩存 – 如果在浏覽器緩存裡沒有找到需要的記錄,浏覽器會做一個系統調用(windows裡是gethostbyname)。這樣便可獲得系統緩存中的記錄。

路由器緩存 – 接着,前面的查詢請求發向路由器,它一般會有自己的dns緩存。

isp dns 緩存 – 接下來要check的就是isp緩存dns的伺服器。在這一般都能找到相應的緩存記錄。

遞歸搜尋 – 你的isp的dns伺服器從跟域名伺服器開始進行遞歸搜尋,從.com頂級域名伺服器到facebook的域名伺服器。一般dns伺服器的緩存中會有.com域名伺服器中的域名,是以到頂級伺服器的比對過程不是那麼必要了。

dns遞歸查找如下圖所示:

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

dns有一點令人擔憂,這就是像wikipedia.org 或者 facebook.com這樣的整個域名看上去隻是對應一個單獨的ip位址。還好,有幾種方法可以消除這個瓶頸:

循環 dns 是dns查找時傳回多個ip時的解決方案。舉例來說,facebook.com實際上就對應了四個ip位址。

負載平衡器 是以一個特定ip位址進行偵聽并将網絡請求轉發到叢集伺服器上的硬體裝置。

一些大型的站點一般都會使用這種昂貴的高性能負載平衡器。

地理 dns 根據使用者所處的地理位置,通過把域名映射到多個不同的ip位址提高可擴充性。這樣不同的伺服器不能夠更新同步狀态,但映射靜态内容的話非常好。

anycast 是一個ip位址映射多個實體主機的路由技術。

美中不足,anycast與tcp協定适應的不是很好,是以很少應用在那些方案中。

大多數dns伺服器使用anycast來獲得高效低延遲的dns查找。

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

因為像facebook首頁這樣的動态頁面,打開後在浏覽器緩存中很快甚至馬上就會過期,毫無疑問他們不能從中讀取。

是以,浏覽器将把一下請求發送到facebook所在的伺服器:

get 這個請求定義了要讀取的url: “http://facebook.com/”。 浏覽器自身定義 (user-agent 頭), 和它希望接受什麼類型的相應 (accept andaccept-encoding 頭). connection頭要求伺服器為了後邊的請求不要關閉tcp連接配接。

請求中也包含浏覽器存儲的該域名的cookies。可能你已經知道,在不同頁面請求當中,cookies是與跟蹤一個網站狀态相比對的鍵值。這樣cookies會存儲登入使用者名,伺服器配置設定的密碼和一些使用者設定等。cookies會以文本文檔形式存儲在客戶機裡,每次請求時發送給伺服器。

用來看原始http請求及其相應的工具很多。作者比較喜歡使用fiddler,當然也有像firebug這樣其他的工具。這些軟體在網站優化時會幫上很大忙。

除了擷取請求,還有一種是發送請求,它常在送出表單用到。發送請求通過url傳遞其參數(e.g.: http://robozzle.com/puzzle.aspx?id=85)。發送請求在請求正文頭之後發送其參數。

像“http://facebook.com/”中的斜杠是至關重要的。這種情況下,浏覽器能安全的添加斜杠。而像“http: //example.com/folderorfile”這樣的位址,因為浏覽器不清楚folderorfile到底是檔案夾還是檔案,是以不能自動添加 斜杠。這時,浏覽器就不加斜杠直接通路位址,伺服器會響應一個重定向,結果造成一次不必要的握手。 

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

圖中所示為facebook伺服器發回給浏覽器的響應:

伺服器給浏覽器響應一個301永久重定向響應,這樣浏覽器就會通路“http://www.facebook.com/” 而非“http://facebook.com/”。

為什麼伺服器一定要重定向而不是直接發會使用者想看的網頁内容呢?這個問題有好多有意思的答案。

其中一個原因跟搜尋引擎排名有 關。你看,如果一個頁面有兩個位址,就像http://www.igoro.com/ 和http://igoro.com/,搜尋引擎會認為它們是兩個網站,結果造成每一個的搜尋連結都減少進而降低排名。而搜尋引擎知道301永久重定向是 什麼意思,這樣就會把通路帶www的和不帶www的位址歸到同一個網站排名下。

還有一個是用不同的位址會造成緩存友好性變差。當一個頁面有好幾個名字時,它可能會在緩存裡出現好幾次。

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

現在,浏覽器知道了“http://www.facebook.com/”才是要通路的正确位址,是以它會發送另一個擷取請求:

頭資訊以之前請求中的意義相同。

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

伺服器接收到擷取請求,然後處理并傳回一個響應。

這表面上看起來是一個順向的任務,但其實這中間發生了很多有意思的東西- 就像作者部落格這樣簡單的網站,何況像facebook那樣通路量大的網站呢!

web 伺服器軟體

web伺服器軟體(像iis和阿帕奇)接收到http請求,然後确定執行什麼請求處理來處理它。請求處理就是一個能夠讀懂請求并且能生成html來進行響應的程式(像asp.net,php,ruby...)。

舉 個最簡單的例子,需求處理可以以映射網站位址結構的檔案層次存儲。像http://example.com/folder1/page1.aspx這個地 址會映射/httpdocs/folder1/page1.aspx這個檔案。web伺服器軟體可以設定成為位址人工的對應請求處理,這樣 page1.aspx的釋出位址就可以是http://example.com/folder1/page1。

請求處理

請求處理閱讀請求及它的參數和cookies。它會讀取也可能更新一些資料,并講資料存儲在伺服器上。然後,需求處理會生成一個html響應。

所 有動态網站都面臨一個有意思的難點 -如何存儲資料。小網站一半都會有一個sql資料庫來存儲資料,存儲大量資料和/或通路量大的網站不得不找一些辦法把資料庫配置設定到多台機器上。解決方案 有:sharding (基于主鍵值講資料表分散到多個資料庫中),複制,利用弱語義一緻性的簡化資料庫。

委 托工作給批處理是一個廉價保持資料更新的技術。舉例來講,fackbook得及時更新新聞feed,但資料支援下的“你可能認識的人”功能隻需要每晚更新 (作者猜測是這樣的,改功能如何完善不得而知)。批處理作業更新會導緻一些不太重要的資料陳舊,但能使資料更新耕作更快更簡潔。

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

圖中為伺服器生成并傳回的響應:

整個響應大小為35kb,其中大部分在整理後以blob類型傳輸。

内容編碼頭告訴浏覽器整個響應體用gzip算法進行壓縮。解壓blob塊後,你可以看到如下期望的html:

關于壓縮,頭資訊說明了是否緩存這個頁面,如果緩存的話如何去做,有什麼cookies要去設定(前面這個響應裡沒有這點)和隐私資訊等等。

請注意報頭中把content-type設定為“text/html”。報頭讓浏覽器将該響應内容以html形式呈現,而不是以檔案形式下載下傳它。浏覽器會根據報頭資訊決定如何解釋該響應,不過同時也會考慮像url擴充内容等其他因素。

在浏覽器沒有完整接受全部html文檔時,它就已經開始顯示這個頁面了:

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?
[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

在浏覽器顯示html時,它會注意到需要擷取其他位址内容的标簽。這時,浏覽器會發送一個擷取請求來重新獲得這些檔案。

下面是幾個我們通路facebook.com時需要重擷取的幾個url:

圖檔

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

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

css 式樣表

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

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

javascript 檔案

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

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

這些位址都要經曆一個和html讀取類似的過程。是以浏覽器會在dns中查找這些域名,發送請求,重定向等等...

但 不像動态頁面那樣,靜态檔案會允許浏覽器對其進行緩存。有的檔案可能會不需要與伺服器通訊,而從緩存中直接讀取。伺服器的響應中包含了靜态檔案儲存的期限 資訊,是以浏覽器知道要把它們緩存多長時間。還有,每個響應都可能包含像版本号一樣工作的etag頭(被請求變量的實體值),如果浏覽器觀察到檔案的版本 etag資訊已經存在,就馬上停止這個檔案的傳輸。

試着猜猜看“fbcdn.net”在位址中代表什麼?聰明的答案是"facebook内容分發網絡"。facebook利用内容分發網絡(cdn)分發像圖檔,css表和javascript檔案這些靜态檔案。是以,這些檔案會在全球很多cdn的資料中心中留下備份。

靜态内容往往代表站點的帶寬大小,也能通過cdn輕松的複制。通常網站會使用第三方的cdn。例如,facebook的靜态檔案由最大的cdn提供商akamai來托管。

舉例來講,當你試着ping static.ak.fbcdn.net的時候,可能會從某個akamai.net伺服器上獲得響應。有意思的是,當你同樣再ping一次的時候,響應的伺服器可能就不一樣,這說明幕後的負載平衡開始起作用了。

[IT]當你在浏覽器位址欄輸入一個URL後輸入,将會發生的事情?

在web 2.0偉大精神的指引下,頁面顯示完成後用戶端仍與伺服器端保持着聯系。

以 facebook聊天功能為例,它會持續與伺服器保持聯系來及時更新你那些亮亮灰灰的好友狀态。為了更新這些頭像亮着的好友狀态,在浏覽器中執行的 javascript代碼會給伺服器發送異步請求。這個異步請求發送給特定的位址,它是一個按照程式構造的擷取或發送請求。還是在facebook這個例 子中,用戶端發送給http://www.facebook.com/ajax/chat/buddy_list.php一個釋出請求來擷取你好友裡哪個 線上的狀态資訊。

提起這個模式,就必須要講講"ajax"-- “異步javascript 和 xml”,雖然伺服器為什麼用xml格式來進行響應也沒有個一清二白的原因。再舉個例子吧,對于異步請求,facebook會傳回一些javascript的代碼片段。

除了其他,fiddler這個工具能夠讓你看到浏覽器發送的異步請求。事實上,你不僅可以被動的做為這些請求的看客,還能主動出擊修改和重新發送它們。ajax請求這麼容易被蒙,可着實讓那些計分的線上遊戲開發者們郁悶的了。(當然,可别那樣騙人家~)

facebook聊天功能提供了關于ajax一個有意思的問題案例:把資料從伺服器端推送到用戶端。因為http是一個請求-響應協定,是以聊天伺服器不能把新消息發給客戶。取而代之的是用戶端不得不隔幾秒就輪詢下伺服器端看自己有沒有新消息。

這些情況發生時長輪詢是個減輕伺服器負載挺有趣的技術。如果當被輪詢時伺服器沒有新消息,它就不理這個用戶端。而當尚未逾時的情況下收到了該客戶的新消息,伺服器就會找到未完成的請求,把新消息做為響應傳回給用戶端。