當我們在瀏覽器的地址欄輸入 www.linux178.com ,然后回車,回車這一瞬間到看到頁面到底發生了什么呢?
整個流程如下:
- 域名解析 -->
- 發起TCP的3次握手 -->
- 建立TCP連接后發起http請求 -->
- 服務器響應http請求,瀏覽器得到html代碼 -->
- 瀏覽器解析html代碼,并請求html代碼中的資源(如js、css、圖片等) -->
- 瀏覽器對頁面進行渲染呈現給用戶
以下就是上面過程的一一分析,我們就以Chrome瀏覽器為例:
域名解析
首先Chrome瀏覽器會解析 www.linux178.com 這個域名對應的IP地址。怎么解析到對應的IP地址?
Chrome瀏覽器會首先搜索瀏覽器自身的DNS緩存(緩存時間比較短,大概只有1分鐘,且只能容納1000條緩存)。
如果瀏覽器自身緩存找不到則會查看系統的DNS緩存,如果找到且沒有過期則停止搜索解析到此結束.
而如果本機沒有找到DNS緩存,則瀏覽器會發起一個DNS的系統調用,就會向本地配置的首選DNS服務器發起域名解析請求(通過的是UDP協議向DNS的53端口發起請求,這個請求是遞歸的請求,也就是運營商的DNS服務器必須得提供給我們該域名的IP地址),運營商的DNS服務器首先查找自身的緩存,找到對應的條目,且沒有過期,則解析成功。如果沒有找到對應的條目,則有運營商的DNS代我們的瀏覽器發起迭代DNS解析請求,它首先是會找根域的DNS的IP地址(這個DNS服務器都內置13臺根域的DNS的IP地址),找打根域的DNS地址,就會向其發起請求(請問www.linux178.com這個域名的IP地址是多少啊?),根域發現這是一個頂級域com域的一個域名,于是就告訴運營商的DNS我不知道這個域名的IP地址,但是我知道com域的IP地址,你去找它去,于是運營商的DNS就得到了com域的IP地址,又向com域的IP地址發起了請求(請問www.linux178.com這個域名的IP地址是多少?),com域這臺服務器告訴運營商的DNS我不知道www.linux178.com這個域名的IP地址,但是我知道linux178.com這個域的DNS地址,你去找它去,于是運營商的DNS又向linux178.com這個域名的DNS地址(這個一般就是由域名注冊商提供的,像萬網,新網等)發起請求(請問www.linux178.com這個域名的IP地址是多少?),這個時候linux178.com域的DNS服務器一查,誒,果真在我這里,于是就把找到的結果發送給運營商的DNS服務器,這個時候運營商的DNS服務器就拿到了www.linux178.com這個域名對應的IP地址,并返回給Windows系統內核,內核又把結果返回給瀏覽器,終于瀏覽器拿到了www.linux178.com對應的IP地址,該進行一步的動作了。
發起TCP的3次握手
拿到域名對應的IP地址之后,User-Agent(一般是指瀏覽器)會以一個隨機端口(1024< 端口 < 65535)向服務器的WEB程序(常用的有httpd,nginx等)80端口發起TCP的連接請求。這個連接請求(原始的http請求經過TCP/IP4層模型的層層封包)到達服務器端后(這中間通過各種路由設備,局域網內除外),進入到網卡,然后是進入到內核的TCP/IP協議棧(用于識別該連接請求,解封包,一層一層的剝開),還有可能要經過Netfilter防火墻(屬于內核的模塊)的過濾,最終到達WEB程序(本文就以Nginx為例),最終建立了TCP/IP的連接。
為什么HTTP協議要基于TCP來實現?
TCP是一個端到端的可靠的面向連接的協議,所以HTTP基于傳輸層TCP協議不用擔心數據的傳輸的各種問題。
建立TCP連接后發起http請求
進過TCP3次握手之后,瀏覽器發起了http的請求,使用的http的方法 GET 方法,請求的URL是 / ,協議是HTTP/1.0

下面是第12號包的詳細內容:

以上的報文是HTTP請求報文。
那么HTTP請求報文和響應報文會是什么格式呢?
個HTTP請求報文由請求行(request line),請求頭部(header),
空行和請求數據4個部分組成,下圖給出了請求報文的一般格式。
請求行
請求行由請求方法字段、URL字段和HTTP協議版本字段3個字段組成,它們用空格分隔。例如,GET /index.html HTTP/1.1。
HTTP協議的請求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。這里介紹最常用的GET方法和POST方法。
- GET:當客戶端要從服務器中讀取文檔時,使用GET方法。GET方法要求服務器將URL定位的資源放在響應報文的數據部分,回送給客戶端。使用GET方法時,請求參數和對應的值附加在URL后面,利用一個問號(“?”)代表URL的結尾與請求參數的開始,傳遞參數長度受限制。例如,/index.jsp?id=100&op=bind。
- POST:當客戶端給服務器提供信息較多時可以使用POST方法。POST方法將請求參數封裝在HTTP請求數據中,以名稱/值的形式出現,可以傳輸大量數據。
請求頭部
請求頭部由關鍵字/值對組成,每行一對,關鍵字和值用英文冒號“:”分隔。請求頭部通知服務器有關于客戶端請求的信息,典型的請求頭有:
User-Agent:產生請求的瀏覽器類型。
Accept:客戶端可識別的內容類型列表。
Host:請求的主機名,允許多個域名同處一個IP地址,即虛擬主機。
空行
最后一個請求頭之后是一個空行,發送回車符和換行符,通知服務器以下不再有請求頭。
請求數據
請求數據不在GET方法中使用,而是在POST方法中使用。POST方法適用于需要客戶填寫表單的場合。與請求數據相關的最常使用的請求頭是Content-Type和Content-Length。
那么起始行中的請求方法有哪些種呢?
GET: 完整請求一個資源 (常用)
HEAD: 僅請求響應首部
POST:提交表單 (常用)
PUT: 上傳
DELETE:刪除
那什么是URL、URI、URN?
URI Uniform Resource Identifier 統一資源標識符
URL Uniform Resource Locator 統一資源定位符 格式如下: scheme://[username:password@]HOST:port/path/to/source http://www.magedu.com/downloads/nginx-1.5.tar.gzURN Uniform Resource Name 統一資源名稱URL和URN 都屬于 URI為了方便就把URL和URI暫時都通指一個東西
請求的協議有哪些種?
有以下幾種:
http/0.9: statelesshttp/1.0: MIME, keep-alive (保持連接), 緩存http/1.1: 更多的請求方法,更精細的緩存控制,持久連接(persistent connection) 比較常用
下面是Chrome發起的http請求報文頭部信息

其中
Accept 就是告訴服務器端,我接受那些MIME類型Accept-Encoding 這個看起來是接受那些壓縮方式的文件Accept-Lanague 告訴服務器能夠發送哪些語言 Connection 告訴服務器支持keep-alive特性Cookie 每次請求時都會攜帶上Cookie以方便服務器端識別是否是同一個客戶端Host 用來標識請求服務器上的那個虛擬主機,比如Nginx里面可以定義很多個虛擬主機 那這里就是用來標識要訪問那個虛擬主機。User-Agent 用戶代理,一般情況是瀏覽器,也有其他類型,如:wget curl 搜索引擎的蜘蛛等 條件請求首部:If-Modified-Since 是瀏覽器向服務器端詢問某個資源文件如果自從什么時間修改過,那么重新發給我,這樣就保證服務器端資源 文件更新時,瀏覽器再次去請求,而不是使用緩存中的文件安全請求首部:Authorization: 客戶端提供給服務器的認證信息;
服務器端響應http請求,瀏覽器得到html代碼
服務器端WEB程序接收到http請求以后,就開始處理該請求,處理之后就返回給瀏覽器html文件。

第32號包 是服務器返回給客戶端http響應包(200 ok 響應的MIME類型是text/html),代表這一次客戶端發起的http請求已成功響應。200 代表是的 響應成功的狀態碼,還有其他的狀態碼如下:
1xx: 信息性狀態碼 100, 101
2xx: 成功狀態碼 200:OK
3xx: 重定向狀態碼
301: 永久重定向, Location響應首部的值仍為當前URL,因此為隱藏重定向;
302: 臨時重定向,顯式重定向, Location響應首部的值為新的URL
304:Not Modified 未修改,比如本地緩存的資源文件和服務器上比較時,發現并沒有修改,服務器返回一個304狀態碼, 告訴瀏覽器,你不用請求該資源,直接使用本地的資源即可。
4xx: 客戶端錯誤狀態碼
404: Not Found 請求的URL資源并不存在
5xx: 服務器端錯誤狀態碼
500: Internal Server Error 服務器內部錯誤
502: Bad Gateway 前面代理服務器聯系不到后端的服務器時出現
504:Gateway Timeout 這個是代理能聯系到后端的服務器,但是后端的服務器在規定的時間內沒有給代理服務器響應
瀏覽器解析html代碼,并請求html代碼中的資源
瀏覽器拿到index.html文件后,就開始解析其中的html代碼,遇到js/css/image等靜態資源時,就向服務器端去請求下載(會使用多線程下載,每個瀏覽器的線程數不一樣),這個時候就用上keep-alive特性了,建立一次HTTP連接,可以請求多個資源。
瀏覽器在請求靜態資源時(在未過期的情況下),向服務器端發起一個http請求(詢問自從上一次修改時間到現在有沒有對資源進行修改),如果服務器端返回304狀態碼(告訴瀏覽器服務器端沒有修改),那么瀏覽器會直接讀取本地的該資源的緩存文件。

瀏覽器對頁面進行渲染呈現給用戶
最后,瀏覽器利用自己內部的工作機制,把請求到的靜態資源和html代碼進行渲染,渲染之后呈現給用戶。