在瀏覽器地址欄輸入一個URL後回車,背後會進行哪些技術步驟?

一個老問題了,希望在知乎上有更加詳細深入的回答,謝謝


我想對於很多非CS專業的人來說,排名最高的答案可能過於專業,很難看完並且看明白。而且大家可能只是想了解一下,所以我就寫了這麼一篇答案,中間跳過了很多細節,並且也沒有說如果發生了錯誤什麼的要怎樣之類的。

我們假設Chrome瀏覽器是專門負責根據URL尋找並打開網頁的人。
-----------
昨天,Chrome先生的老闆給了他一個URL地址,並對他說:「去吧,Chrome!」

步驟0:識別URL
Chrome先生低頭看了看老闆給的URL,完整的URL是由協議(比如http,ftp)、域名(比如http://www.baidu.com)、文件路徑(比如/htm_data/20/1510/1441477.html這樣的)和埠(比如:80)四個部分組成的,老闆只給了域名http://www.zhihu.com,不過沒關係。
「這就夠了。」Chrome先生自信的一笑,走向了老闆。

步驟1.查找本地hosts文件
「雖然老闆已經給了我URL地址,但是網頁(文件)是保存在伺服器上的,要找到老闆要的東西就要找到保存文件的伺服器,要找到伺服器就要先知道伺服器的IP地址。」Chrome先生如是想。
Chrome從老闆的抽屜里找出一個筆記本。
老闆好奇的問:「Chrome,為什麼每次我要你給我打開個網頁你都要看看這個破本子,這到底是幹什麼的?」
Chrome:「hosts文件,用來保存域名以及域名對應的IP地址。」
Chrome打開一看,不出所料,裡面空空如也,於是Chrome又把筆記本放回了原處。
老闆好奇地問:」Chrome,為什麼裡面是空的?」
「因為你不會科學上網啊,把一個網站的域名寫到這個文件里,寫一個空格,後面再加上一個該網站可以用的伺服器的IP地址,以後訪問這個網站的話就會直接訪問這個IP對應的伺服器了。」

步驟2.1詢問本地域名伺服器
Chrome看了看手裡的域名,「越高級的域名越靠後,必須要先找後面的域名,然後才能進一步的找到整個域名啊。」
Chrome用自己的手機撥了一個神秘的電話。
老闆好奇的問:「Chrome,你在跟誰打電話?」
Chrome:「地兒,我一朋友,是個本地域名伺服器,哎呀你不認識。」
對方很快接通了。
Chrome:」喂,地兒嗎?哎對,是我,問你個事兒,www.baidu.com 這個網址你見過沒?……什麼?咱們這附近沒人上過這個網站?昂……你給我查查?哎……行行行……哎好嘞,沒事,不著急啊。「
說完Chrome並沒有掛掉電話,依舊把手機放在耳朵邊上聽著,還抽空跟老闆解釋了一句:「根兒也不知道。」
老闆好奇的問:「你掛了電話讓他打回來不就行了?」
Chrome:「就不。」

步驟2.2詢問根域名伺服器
話分兩頭,這邊的本地域名伺服器又拿起一部手機,打開了一個叫「找根兒」的APP。
這個找根兒APP是幹嘛的呢?顧名思義,就是用來找根域名伺服器的了,要知道全世界有數百個根域名伺服器,簡而言之,「找根兒」可以幫你找到通話質量最好的那個。
我們還是叫他地兒吧。
地兒:「喂,您好,麻煩幫我查一下com這個頂級域名的域名伺服器的IP地址。」
神秘的對方一號:「好的,您要查的IP地址是:2.3.4.5,感謝您的來電,再見。」說完掛了電話。
地兒又給2.3.4.5播了個電話:「喂,您好,我想查一下你們那個zhihu的二級域名的域名伺服器地址。」
神秘的對方二號:「好的,您要查的IP地址是:3.4.5.6,感謝您的來電,再見。」說完掛了電話。
地兒又不厭其煩的給3.4.5.6撥了個電話:「喂,您好,我想查一下你們那個wwwl的三級域名的域名伺服器地址。」
神秘的對方三號:「好的,你要查的IP地址是:4.5.6.7,感謝您的來電,再見。」說完掛了電話。
地兒看了看,地址里沒有更低一級的域名了,就拿起跟Chrome通話的電話:「哎,Chrome,還在吧?……對,查出來了……恩,4.5.6.7……恩……恩……好……哎,沒事沒事……好,再見,替我跟IE問好啊,好長時間沒見他了……好……好,再見……哎……好……好。」

步驟3.1根據IP地址訪問伺服器
掛掉了地兒的電話,Chrome撥通了4.5.6.7,這時的老闆似乎有點等不及了。
很快,對方接通了電話。
神秘的對方四號:「您好,需要什麼服務?」
Chrome:「你好,主頁就好了。」
神秘的對方四號:「好的,我們注意到您是第一次訪問我們頁面,現在向您發送確認頁面。」
Chrome:「……什麼鬼?」
神秘的對方四號並沒有理Chrome先生,它發給了Chrome先生一個HTML文檔,Chrome把這個HTML文檔解析成了彩色的網頁,展示給了老闆。
老闆輸入完用戶名、密碼還有驗證碼以後,點擊了提交。
這一次Chrome不用像第一次那麼麻煩了,不過他依然先打開了老闆的hosts文件看了看,確定老闆沒有強制的網址跟IP的映射關係(就是某個網址一定要去某個IP訪問),然後自己回憶了一下剛剛的操作,就直接撥通了4.5.6.7。
神秘的對方四號對Chrome先生說:「恭喜您登陸成功,現在對您發送一條cookie記錄,這樣您以後再訪問我們網站的時候一塊兒把這串cookie發過來,我就知道您以前登陸過我們網站,就不會再出現剛剛的登陸頁面了,請注意接收。」
Chrome:」好……「
神秘的對方四號等Chrome保存好cookie記錄之後,接著說:「現在為您跳轉到主頁,請注意查收。」
說完,就給Chrome發來了一個html文件。
Chrome照例解析這個html文件成網頁給老闆看。
Chrome:「沒事我先撤了哈。」

---- end ---

感覺不錯的話點個贊啊!


計算機網路龐大且複雜,很難一言或幾言以蔽之。因此,這裡我們只考慮最一般的場景,所謂「一般」,就是...比如,沒有緩存,客戶機和伺服器不在一個區域網,輸入的是一個域名而不是IP地址,etc。我們採用自頂向下的方法,也是時間順序的方法,來解答這個問題。瀏覽器是C/S架構中的客戶端,通過想伺服器發送請求,獲取文件(html,js,css等),再通過瀏覽器引擎的解釋和渲染,將這些文件呈現成你現在看到的樣子。
1、TCP/IP參考模型
首先,我們不得不了解一下TCP/IP參考模型。
如下圖所示,TCP/IP參考模型分為四層:應用層、運輸層、網路層和介面層。瀏覽器所完成的工作就屬於應用層的範疇。

  • 應用層: 為用戶提供各種服務,比如我們瀏覽網頁時用到的HTTP,收發郵件時用的SMTP,登錄遠程主機用的SSH。
  • 傳輸層:提供端到端的傳輸服務。更具體地講,提供進程到進程的傳輸服務。
  • 網路層:和傳輸層一樣,可以概括為提供端到端的傳輸服務。更具體地講,網路層提供主機到主機的傳輸服務。
  • 網路介面層(鏈路層):為直接連接的設備提供傳輸服務,將數據幀轉換為比特流,並將比特流轉換為物理電路的電壓高低信號。

2、往哪裡發送請求?
假設我么輸入的地址是

zhihu.com

瀏覽器看到這個域名的時候,就好像我們想去一家從沒去過的餐廳吃飯,只知道名字是「黃大仙腸粉」但不知道具體地點在哪裡。這個時候,我們打開地圖,搜索「黃大仙腸粉」後找到一個地址:衡山路110號,於是我們便知道該去哪了。域名就像是一個餐廳的名字,而IP地址相當於一個具體的地址。瀏覽器必須知道所請求伺服器的IP地址,發出的請求才有目的地。DNS(Domain Name System)提供的服務就是將知乎的域名轉換成其伺服器IP地址。
DNS具有兩層含義:①一個由分層的DNS伺服器實現的分散式資料庫;②一個允許主機查詢分散式資料庫的應用層協議。有三種類型的DNS伺服器:根DNS伺服器、頂級DNS伺服器和權威DNS伺服器。這些伺服器以下圖的層次結構組織起來。

除此之外,還有一類重要的DNS,稱為本地DNS伺服器。嚴格來說本地DNS伺服器並不屬於DNS伺服器的層次結構,但它在整個查詢的過程中卻扮演著重要的角色。
首先,瀏覽器所在的主機向本地DNS伺服器發送一個含有知乎域名的DNS查詢報文。本地DNS伺服器把查詢報文轉發到根DNS伺服器,該根DNS伺服器注意到其com後綴並向本地DNS伺服器返回com的頂級域名伺服器的IP地址。該本地DNS伺服器再次向comDNS伺服器發送查詢請求,comDNS伺服器注意到其http://zhihu.com後綴並用負責該域名的權威DNS伺服器的IP地址作為回應。最後,本地域名伺服器將含有http://zhihu.com的IP地址的響應報文發送給客戶端主機。

這裡的查詢過程是包含遞歸查詢和迭代查詢的,客戶端主機發送給本地伺服器的查詢是遞歸查詢,而後面的三個查詢是迭代查詢。最高票 @郭無心 的答案中給出的遞歸查詢應該是迭代查詢才對。
2、封裝HTTP請求
其實這裡主要講HTTP報文的格式的。可以看到,這個請求裡面包含了請求的方法GET,請求的路徑「/」,請求的主機名,客戶機的類型以及一些其他的信息。

GET / HTTP/1.1
Host: zhihu.com
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64;
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

前面辛辛苦苦通過DNS獲得的IP地址怎麼沒有用到?HTTP請求報文里根本沒有這一個欄位。繼續往下看。
3、建立連接
在應用層和傳輸層之間,更準確地講是在瀏覽器進程和操作系統提供的TCP服務程序之間,有一個很重要的東西叫做套接字(Socket),如下圖所示。如果把一台主機比作一座房子,把進程比作房子裡面的房間,Socket相當於房間的門。不管是房間的人要出來還是外面的人要去到某一個房間,都必須先通過Socket這一道門。套接字的作用是實現傳輸層的多路復用和多路分解。在應用層可以同時運行多個進程,每個進程都需要通過傳輸層來收發分組,而傳輸層的TCP進程只有一個,當TCP進程收到一個分組後,該怎麼確定應該轉發給哪個進程呢?答案是通過套接字,這就是多路分解。同樣的道理,多路復用就是進程將分組通過各自的套接字轉發給傳輸層。TCP套接字是由一個四元組(源IP地址、源埠號、目的IP地址和目的埠號)來標識的。

TCP是面向連接的,在實際發送數據之前,客戶端和伺服器需要建立起一個TCP連接。這種TCP「連接」只是邏輯上的鏈接,因為其狀態完全保留在兩個端系統中,中間路由器對TCP連接毫不知情。
TCP連接的建立過程如下圖所示。首先,TCP先發送一個創建連接的SYN請求,告訴伺服器主機「我想和你創建一條TCP連接」。當伺服器主機收到SYN請求後,如果其所請求的埠號正在等待連接,則會為這一條TCP連接分配資源,並發送一個SYNACK報文段作為應答。客戶主機收到SYNACK報文段後,客戶機也為該連接分配資源。此時,連接已經建立起來了。客戶主機還會向伺服器主機發送另一個報文段,對允許連接的報文段進行確認。這就是有名的「三次握手」。

可以這樣簡單地認為,TCP連接創建成功的標誌是:客戶機和伺服器都創建了一個由源IP地址、源埠號、目的IP地址和目的埠號標誌的Socket。
4、發送請求
請求在「三次握手」的第三次「握手」就發送出去了。
TCP報文段的格式如下圖所示。

目的埠和源埠號是為了在多路復用和多路分解時選擇套接字時使用的。
數據序號和確認序號是為了傳輸數據的完整性和順序而設置的。
用戶數據這一個欄位就存儲了應用層生成的HTTP報文。
ACK、SYN和FIN是在建立連接和關閉連接時使用。
其他用於流量控制、擁塞管理等用途的字元就不展開了。
5、路由定址
現在兩個端系統已經建立起了連接,請求也被傳送到客戶端主機的網路層。網路層是協議棧中最複雜的層次,應用層和傳輸層只運行在兩個端系統,而網路層不僅運行在端系統,還運行在各個中間節點上。
我們先來看看IP數據報的格式。

網路層實現的最重要的功能是路由選擇,簡單地說,就是怎麼把這一個IP數據報從客戶端主機出發,通過網路中的若干個路由器,到達目的主機。從概念上講,IP路由選擇是簡單的,特別對於主機來說,如果目的主機和源主機直接相連(如點對點鏈路),或都在一個共享網路上(乙太網或令牌環網),那麼IP數據報就直接送到目的主機上。否則,主機把數據報發送到一默認的路由器上,由路由器來轉發該數據報。大多數的主機都採用這種簡單機制。
我們把網路環境簡化如下圖:只包含源主機H1、目的主機H2和兩個路由器R1、R2。

IP路由選擇是逐跳(hop-to-hop)進行的。IP並不知道從H1到H2的完整路徑。所有的IP選擇只為數據報提供下一站的IP地址。路由選擇機制的基礎是在每一台主機和路由器里都存儲著一張路由表。路由表的每一項包含了目的主機IP地址、下一跳路由器(或主機)的IP地址、相對應的網路介面以及其他必要的信息。當一個數據報到達一個節點時,IP路由選擇完成以下工作:

  1. 搜索路由表,尋找能與目的主機IP地址完全匹配的表目。如果找到,則把報文發送給下一跳節點。
  2. 搜索路由表,尋找能與目標網路號相匹配的表目。如果找到,則把報文發送給下一跳節點。
  3. 搜索路由表,尋找「默認」的表目。如果找到,則把報文發送給下一跳節點。

如果上面這些步驟都沒有成功,那麼該數據報就不能被傳送。如果不能傳送的數據報來自本機,那麼一般會向生成數據報的應用程序返回一個「主機不可達」或「網路不可達」的錯誤。
在我們的例子中,H1通過搜索自己的路由表將數據報轉發給R1,R1根據路由錶轉發給R2,最後到達H2。
6、關閉連接
目標主機收到了請求後,自底向上地對該請求進行處理。鏈路層把數據報傳給網路層,網路層將TCP數據段通過對應的Socket傳給應用程序。應用程序處理請求後產生一個應答的HTTP報文,又經過了一層層的封裝、一跳跳的傳輸到達了源主機。
這樣就結束了嗎?那一條TCP連接還沒有關閉呢,源主機和目標主機上都為它分配了資源呢,如果不釋放掉的話資源很快就會耗盡(DDoS攻擊就是利用這一點)。於是,當傳輸層收到了應答之後,就要關閉這條連接了。但是,又不能悄悄地自己關了,目標主機那邊還不知道你要不要關閉呢。於是乎,就有了對應創建TCP連接「三次握手」的關閉TCP連接「四次揮手」。
如下圖所示,客戶端向伺服器發出了FIN報文段,伺服器收到後,回復一個ACK應答。然後,伺服器也向客戶端發送一個FIN報文段,隨後關閉了伺服器端的連接,釋放了資源。當客戶端收到之後,又向伺服器回復一個ACK應答。過了一段計時等待,客戶端也關閉了連接,釋放資源。這一段計時等待的時間是為了客戶端重傳最後的ACK防止其丟失。

剩下的事情,就交給瀏覽器了。


點擊查看大圖

圖片源自 Brendan Fortuner

關於這張圖的解析,會在知乎專欄 前端指南 中持續更新,主要章節有:

  1. 客戶端(當你點擊按鈕時發生了什麼?)
  2. 計算機網路(信息是如何通過網路傳播的?)
  3. 網路安全(如何避免黑客盜取我們的密碼?)
  4. 伺服器(「雲端」到底是什麼?)
  5. 應用(Web伺服器和Web框架到底是什麼?)
  6. 資料庫(Web應用如何在資料庫中檢索數據?SQL vs NoSQL?)
  7. 大規模(如何處理大規模請求)
  8. 渲染(瀏覽器是如何工作的?)

歡迎關注


我還以為大家都知道這個優秀資源呢,整個互聯網最好的答案: What really happens when you navigate to a URL


答案不是應該從回車鍵的電流迴路閉合開始講起嗎

============================
找到了原文。。。
http://blog.jobbole.com/84870/


又是祭出這個鏈接的時候了 https://github.com/skyline75489/what-happens-when-zh_CN/blob/master/README.rst


你要面試百度FEX嗎?

這個是百度FEX的參考答案從輸入 URL 到頁面載入完成的過程中都發生了什麼事情?

=========================補充================================
以下個人的答案,回答的重點在瀏覽器伺服器HTTP協議相關內容。

1 瀏覽器如何把提交的數據封裝成HTTP協議格式,相關知識:TCP HTTP。
2 數據在網路中是怎樣流到伺服器的,相關知識:DNS 代理 CDN IP地址 路由 網路結構。
3 伺服器是怎樣解析和處理數據的,相關知識:HTTP 各種web伺服器知識 伺服器相關語言知識(Java Python等) 資料庫(SQL NOSQL)等。
4 處理結束後的結果是怎樣封裝在HTTP協議中返回的,相關知識:HTTP,各種web伺服器知識。
5 瀏覽器得到數據後,又是怎樣處理HTTP響應的,相關知識:HTTP 瀏覽器。
6 瀏覽器和JS如何處理響應數據,DOM如何渲染數據,相關知識:DOM和JS引擎。


簡單來說:
1. 首先是瀏覽器程序開始解析你的地址。把地址分為域名和路徑(如何含有的話)兩個部分,然後連接DNS伺服器,查詢這個域名的IP地址。
2. 獲得DNS返回的IP地址之後,瀏覽器開始按照HTTP協議的格式向該IP地址和路徑請求內容。
3. 伺服器收到某個HTTP請求之後,就會把內容按照HTTP協議的格式返回這個請求的客戶端。
4. 瀏覽器收到伺服器返回的內容後,開始渲染並顯示出來。
5. 瀏覽器與伺服器對話結束。
基本流程就是這樣。


http 權威指南,推薦看看


請獨立準備面試題


反對 @郭無心 的答案

這種從圖片到標題到文字大部分一模一樣不叫參考,叫轉貼
不說是轉貼的叫抄襲,要點臉



這是個細節問題,前兩天正好做了這個實驗,看到這個問題就來說說,如有大神看到不當之處,請指出,若覺得合理,自當改正,若覺得扯淡,保留原答案


==================================

首先,當你在電腦輸入URL時,比如百度,當你在地址欄輸入http://www.baidu.com按回車時,首先你的電腦會發一份icmp請求到dns,當dns沒有回復icmp請求時,你的瀏覽器就會顯示dns錯誤,當dns回復一份icmp應答後,你的電腦會發一份arp請求給dns,然後dns搜索自身的資料庫,有沒有百度的域名對應的ip地址,如果沒有,就向上級dns繼續請求百度域名所對應的ip地址,這裡注意,因為dns是樹形結構的,一級一級的,直到找到了百度的域名所對應的ip地址,若是搜索到根級dns還沒有的話,就會出現網址錯誤,若是找到了百度域名所對應的ip地址,就發出回復告訴下一級dns,然後依次到你所在區域的dns,然後你所在區域的dns伺服器告訴你的電腦百度的ip地址,然後你的電腦內核將ip地址轉換為01代碼,通過網線轉換成比特流,然後奔著得來的ip地址直奔到百度的伺服器

以上,如果看的有些迷糊多看兩遍就會明白細節了,覺得好的請點贊,感謝


從web應用的角度解釋,整個過程包括:
1.瀏覽器發送一個HTTP請求;
2.伺服器收到請求,生成一個HTML文檔;
3.伺服器把HTML文檔作為HTTP響應的Body發送給瀏覽器;
4.瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔並顯示。
所以,最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP伺服器軟體,接收用戶請求,從文件中讀取HTML,返回。Apache、Nginx、Lighttpd等這些常見的靜態伺服器就是干這件事情的。
下面只講 請求和響應:
調用WSGI介面,可以查看最簡單的http請求的包含哪些內容。
在本機開啟伺服器監聽8000埠

寫一個處理Http請求的函數,:將請求的內容列印到瀏覽器上
def application(environ, start_response):
response_body = ["%s: %s" % (key, value)
for key, value in sorted(environ.items())]
response_body = "
".join(response_body)

status = "200 OK"
response_headers = [("Content-Type", "text/plain"),
("Content-Length", str(len(response_body)))]
start_response(status, response_headers)

return [response_body]

打開瀏覽器訪問127.0.0.1:8000,可以看到整個請求里包含Http請求頭的詳細信息,伺服器為127.0.0.1:8000

PATH_INFO:/ 因為請求的URL是127.0.0.1:8000後面沒有任何東西所以是,瀏覽器中可以看到。PATH_INFO就是瀏覽器上輸入的URL這裡只是省略了伺服器信息。修改上面的 application函數,讓瀏覽器訪問127.0.0.1:8000時,返回Hello,Web!

伺服器端顯示是這樣的:

兩次的請求都是一樣的,即都是瀏覽器輸入127.0.0.1:8000訪問伺服器,我們看到的響應不同,只是伺服器處理該請求的函數修改了。 簡單的講,客戶端輸入不一樣的URL請求,伺服器根據PATH_INFO選擇處理這個請求的函數,響應內容全由這個函數來定義。


輸入http://www.baidu.com
1,找到com域名根伺服器
2,從根伺服器找到http://baidu.com域名
3,找到http://baidu.com域名後,再找出域名的dns伺服器
4,從http://baidu.com的dns伺服器中找出域名的dns配置
5,從dns配置中找到www主機頭的指向,也就是ip地址。
6,通過ip找到伺服器
7,伺服器再找到該域名和主機頭綁定的網站應用程序。
8,應用程序響應,再將數據返回。
9,瀏覽器得到數據,渲染展示。


你會進入快樂星球


雖然我之前面試前端同學的時候也喜歡問這個問題,但是這個我廠給出的參考答案真是莫名的可怕。。。誰能回答成這樣啊摔!


會向伺服器發送一個請求,然後伺服器會給源主機發送一個確認請求,然後主機就能從伺服器抓去文件了


上層網路http等網路應用層協議,然後是內核TCP/IP 協議,網卡驅動,到網卡在網線上送接受數據


計網的作業?


推薦閱讀:

TCP快速重傳為什麼是三次冗餘ack,這個三次是怎麼定下來的?
OSI模型中,一個協議應該屬於哪一層是以什麼為標準劃分的?
網關和路由器的區別是什麼?
網路編程必須使用socket嗎?
E2E RTT的具體含義?

TAG:程序員 | 域名 | 計算機 | 計算機網路 | TCPIP |