當咱們在瀏覽器的地址欄鍵入www.linux178.com,而後回車,從回車這一刻到看到頁面到底發生了什麼呢?php
一下咱們已chrome瀏覽器爲例,對上面的過程一一分析。css
一. 域名解析html
首先chrome瀏覽器會解析www.linux178.com這個域名(準確的說法是主機名)對應的IP地址。怎麼解析獲得對應的IP地址呢?node
(1)瀏覽器首先搜索自身的DNS緩存(緩存時間比較短,大概只有1分鐘,且只能容納1000條數據),看自身的緩存中是否有www.linux178.com對應的條目,並且沒有過時,若是有且沒有過時,解析就到此結束。咱們能夠經過在瀏覽器地址欄中輸入:chrome://net-internals/#dns來查看。linux
(2)若是瀏覽器自身的緩存中沒有找到對應的條目,那麼chrome瀏覽器會搜索操做系統自身的DNS緩存,若是找到且沒有過時則中止搜索,解析到此結束。如何查看操做系統自身的DNS緩存,以Windows系統爲例,能夠在cmd命令行中輸入ipconfig/displaydns來查看。nginx
(3)若是在操做系統的DNS緩存中也沒有找到,那麼嘗試讀取hosts文件(位於c:\Windows\System32\direvers\etc),看看這裏有沒有該域名對應的IP地址,若是有則解析成功,解析到此結束。web
(4)若是在hosts文件中也沒有找到對應的條目,瀏覽器會發起一個DNS系統調用,就會向本地配置的首選DNS服務器(通常是電信運營商提供的,也可使用像Google提供的DSN服務器)發起域名解析請求(經過UDP協議向DNS的53號端口發起請求,這個請求是遞歸請求,也就是這個運營商的DSN服務器必須給咱們提供該域名的IP地址)。請求過程以下:正則表達式
注:通常狀況下是不會進行一下步驟的chrome
若是通過以上4個步驟,仍是沒有解析成功,那麼會進行以下步驟(針對Windows操做系統):後端
(5)操做系統就會查找NetBIOS name Cache(NetBIOS名稱緩存,就在客戶端電腦中),這個緩存是什麼東西呢?它是最近一段時間內我和咱們成功通信的計算機名和IP地址,都會存在這個緩存裏面。什麼狀況下該不住能解析成功呢?就是這個計算機名稱正好是幾分鐘前咱們成功通信過的,那麼這一步就能夠解析成功。
(6)若是第5步也沒有成功,那會查詢WINS服務器(NETBIOS名稱和IP地址對應的服務器)。
(7)若是第6步也沒有查詢成功,那麼客戶端就要進行廣播查找。
(8)若是第7步也沒有查詢成功,那麼客戶端就讀取LMHOSTS文件(和hosts文件在同一個目錄下,寫法也同樣)。
若是第8步仍是沒有解析成功,那麼就宣告此次解析失敗,沒法和目標計算機進行通訊。只要這8步中任意一個解析成功,就能夠成功和目標計算進進行通訊。
看下圖的抓包截圖:
Linux虛擬機測試,使用命令wget www.linux178.com來請求,發現直接使用chrome瀏覽器請求時,干擾請求比較多,因此使用wget命令來請求,不過wget命令只能把index.html請求回來,並不會對index.html中包含的靜態資源(js,css等文件)進行請求。
抓包分析:
①號包,這個是那臺虛擬機在廣播,要獲取192.168.100.254(也就是網關)的MAC地址,由於局域網的通訊靠的是MAC地址,它爲何須要和網關進行通訊是由於咱們的DNS服務器IP是外圍IP,要出去必須靠網關幫助才行。
② 號包,這個是網關接收到虛擬機的廣播以後,迴應給虛擬機,告訴虛擬機本身的MAC地址,因而客戶端找到了路由出口。
③號包,這個包是wget命令向系統配置的DNS服務器提出的域名解析請求(準確的說應該是wget發起了一個DNS解析的系統調用),請求的域名www.linux178.com指望獲得的是IP6的地址(AAAA表明IPV6地址)。
④號包,這個DNS服務器給系統的響應,很顯然目前使用IPv6的仍是極少數,所得得不到AAAA記錄。
⑤號包,這個仍是請求解析IPv6地址,可是www.linux178.com.leo.com這個主機名是不存在的,因此獲得的結果是no such name。
⑥號包,這個纔是請求的域名對應的IPv4地址(A記錄)。
⑦號包,DNS服務器無論是從緩存裏,仍是進行迭代檢查最終獲得的域名IP地址,響應給了系統,系統給了wget命令,wegt因而獲得了www.linux178.com的IP地址,這裏能夠看出客戶端和本地DNS服務器是遞歸的查詢(也就是服務器必須給客戶端一個結果)就能夠開始下一步了,進行TCP的三次握手。
二. 發起TCP的3次握手
拿到域名對應的IP地以後,User-Agent(通常是指瀏覽器)會以一個隨機端口(1024<端口<65535)向服務器的web程序(經常使用的有httpd,nginx等)80端口發起TCP的鏈接請求。這個鏈接請求(原始的http請求通過TCP/IP層模型層層包裝)到達服務器後(這中間經過各類路由設備,局域網除外),進入到網卡,而後進入到內核的TCP/IP協議棧(用於識別這個鏈接請求,解封包,一層層剝開),還有可能要通過Netfilter防火牆(屬於內核的模塊)的過濾,最終到達web程序(本文就以Nginx爲例)最終創建TCP/IP鏈接,以下圖:
⑨號包,這個對應上面的步驟1)
⑩號包,這個對應上面的步驟2)
⑪號包,這個對應上面的步驟3)
TCP爲何要進行三次握手?舉一個列子,假如一個老外在故宮迷了路,看到小明,因而就有了下面的對話:
老外:Excuse me,Can you speck English?
小明:Yes
老外:OK, I want to...
在問路以前老外先問小明是否會說英語,小明回答是的,這時老外才開始問路。
兩臺計算機之間的通訊是靠協議(目前流行TCP/IP協議)來實現的,若是兩臺計算機使用的通訊協議不同,那是不能進行通訊的,因此這個3次握手就至關於試探一下對方是否遵循TCP/IP協議,協議完成後就能夠進行通訊了,固然這個說法不是那麼準確。
爲何HTTP協議要基於TCP來實現?
目前在Internet中全部的傳輸都是經過TCP/IP進行的,HTTP協議做爲TCP/IP模型中應用層的協議也不例外,TCP是一個端到端的可靠的面向鏈接的協議,因此HTTP基於傳輸層TCP協議不用擔憂數據傳輸中的各類問題。
三.創建TCP鏈接後發起http請求
通過TCP3次握手以後,瀏覽器發起了http請求,使用的http的GET方法,請求的URL是/,協議是HTTP/1.0
下面是第⑫號包的詳細內容:
以上的報文是HTTP請求的報文。
那麼HTTP請求報文和響應報文是什麼格式呢?
起始行:如GET/HTTP/1.0(請求的方法,請求的URL,請求所使用的協議)
頭部信息:User-Agent Host等成對出現的值
主體:xxx
無論是請求報文仍是響應報文,都遵循以上的格式。
那麼起始行中的請求方法有那些呢?
GET:完整請求一個資源(經常使用)
HEAD:僅請求響應的首部
POST:提交表單(經常使用)
PUT:上傳文件(部分瀏覽器不支持這個方法)
DELETE:刪除
OPTIONS:範秋請求的資源所支持的方法
TRACE:跟蹤一個資源其你去中間所通過的代理(該方法不是由瀏覽器發出)
那什麼是URL,URI,URN呢?
URL:統一資源標識符
URI:統一資源定位符,格式如:scheme://[username:password@]HOST:port/path/to/source,http://www.magedu.com/downloads/nginx-1.5.tar.gz
URN:統一資源名稱
URL和URN都屬於URI,爲了方便就把URL和URI暫時都通指一個東西
請求的協議有那些呢?
http/0.9:stateless
http/1.0:MIME,keep-alive(保持鏈接),緩存
http/1.1:更多的請求方法,更精細的緩存控制,持久鏈接(persistent content)比較經常使用,下面是chrome發起的http請求報文頭部信息:
其中
Accept就是告訴服務器,我接受那些MIME類型
Accept-Encoding:接受那些壓縮方式的文件
Accept-Language:告訴服務器可以發送那些語言
Connection:告訴服務器支持keep-alive特性
Cookie:每次請求都會攜帶上Cookie以方便服務器識別是不是同一個客戶端
Host:用來標識請求服務器的那個虛擬機,好比Nginx裏面能夠定義不少虛擬主機,這裏就是來標識要訪問是哪個
User-Agent:用戶代理,通常狀況是瀏覽器,也有其餘類型,如wget, curl搜索引擎的蜘蛛等
條件請求首部:
If-Modified-Since是瀏覽器向服務器端詢問某個資源文件若是自從什麼時間修改過,那麼從新發送給我,這樣保證服務器資源文件更新時,瀏覽器再次請求,而不是使用緩存中的文件。
安全請求首部:
Anthorization:客戶端提供給服務器的認證信息
什麼是MIME?
MIME:多用途互聯網郵件擴展,是一個互聯網標準,它擴展了電子郵件的標準,使其可以支持非ASCII標準字符,二進制格式附件等多種格式的郵件消息,這個標準被定義在RFC 2045,RFC2046,RFC2047,RFC2048,RFC2049等RFC中。因爲RFC 882轉化而來的RFC2882規定電子郵件標準不容許在郵件消息中使用7位ASCII字符集之外的字符。所以,一些非英語消息和二進制文件,圖像,聲音,等非文字消息不能在電子郵件中傳輸。MIME規定了用於各類各樣的數據類型的符號化方法。此外在萬維網中使用HTTP協議也是用了MIME協議中的框架,標準被擴展爲互聯網媒體類型。
MIME遵循如下格式:major/minor主要類型/次要類型,例如:image/jpg,image/gif,text/html,video/quicktime,application/x-httpd-php。
四. 服務器響應http請求,瀏覽器獲得html代碼
看下圖中第⑫號包是http請求包,第32號包是http響應包,服務器端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 這個是代理能聯繫到後端的服務器,可是後端的服務器在規定的時間內沒有給代理服務器響應
使用chrom瀏覽器能夠看到響應頭消息
Connection:使用keep-alive特性
Content-Encoding:使用gizp方式對資源壓縮
Content-Type:MIME類型爲html類型,字符集是UTF-8
Date:響應的日期
Server:使用的Web服務器
Transfer-Encoding:chunked分塊傳輸碼,是http中的一種數據傳輸基址,容許HTTP由網頁服務器發送給客戶端應用(一般是網頁瀏覽器)的數據能夠分紅多部分
Vary:這個能夠參考(http://blog.csdn.NET/tenfyguo/article/details/5939000)
X-Pingback:參考(http://blog.sina.com.cn/s/blog_bb80041c0101fmfz.html)
到底服務器端接收到http請求後怎樣生成html文件?
假設服務器使用的是nginx+php(fastcgi)架構提供服務。
root /web/echo
經過這個配置就知道全部的網頁文件放在這個目錄下,就是當咱們訪問http:www.linux178.com/時就是訪問這個目錄下面的文件,錄入訪問http://www.linux178.com/index.html,那麼表明web/echo下面有個文件叫index.html。
index index.html index.htm index.php
經過這個就能夠獲得網站的首頁文件是那個文件,也就是咱們在輸入http://www.linux178.com/的時候,nginx就會自動幫咱們把index.html(假設首頁是index.php固然是會嘗試去找到這個,若是沒有找到該文件就以此往下找,若是3個文件都沒有找到,那麼就會拋出一個404錯誤)加到後偶棉,那麼添加後的URI若是是/index.php,而後根據配置進行處理:
location ~ .*\.php(\/.*)*$ { root /web/echo; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; astcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }
這一段配置指明範市請求的URL中配置(這裏啓用了正則表達式進行配置),*.php後綴的(後面跟參數)都交給後端的fastcgi進程進行處理。
還有一個要點:目錄其實也是普通文件,也要佔用磁盤塊,目錄不是一個容器。默認建立的目錄都是4096字節,也就是說只須要佔用一個磁盤塊,可是這個是不肯定的。因此要找到目錄也須要到元數據區裏面找到對應的條目,只有找到對應inode就能夠找到目錄鎖佔用的磁盤塊。
那到底目錄裏面存放着什麼,難道不是文件或者其餘目錄嗎?
其實目錄裏面存着這麼一張表,裏面放着目錄或者文件的名稱和對應的inode號(暫時稱之爲映射表),以下圖:
假設
/ 在數據區佔據 一、2號block ,/其實也是一個目錄 裏面有3個目錄 web 111
web 佔據 5號block 是目錄 裏面有2個目錄 echo data
echo 佔據 11號 block 是目錄 裏面有1個文件 index.php
index. php 佔據 15 16號 block 是文件
其在文件系統中分佈以下圖
name內核到底是怎麼找到index.php這個文件的呢?
內核拿到nginx的IO系統調用要獲取/web/echo/index.php這個文件請求以後:
1.內核讀取元數據 / 的inode,從inode裏讀取/所對應的數據塊的編號,而後再數據區找到對應的(1,2號塊),讀取一號快上的映射表找到web這個名稱在元數據區對應的inode號
2.內核讀取web對應的node(3號),從中得知web在數據區對應的塊是5號塊,因而到數據區找到5號塊,從中讀取映射表,知道echo對應的inode是5號,因而元數據找到5號inode
3.內核讀取5號的inode,獲得echo在數據區對應的是11號塊,因而到數據區讀取11號塊獲得映射表,獲得index.php對應的inode是9號
4.內核到元數據讀取9號inode,獲得index.php對應的是15和16號數據塊,因而在數據區域找到15,16號塊,讀取其中的內容,獲得index.php的完整內容。
五. 瀏覽器解析html代碼,並請求html代碼中的資源
瀏覽器拿到index.html文件後,就開始解析其中的html代碼,遇到js/css/image等靜態資源時,就向服務器端去請求下載(會使用多線程下載,每一個瀏覽器的線程數不同),這個時候就用上keep-alive特性了,創建一次HTTP鏈接,能夠請求多個資源,下載資源的順序就是按照代碼裏的順序,可是因爲每一個資源大小不同,而瀏覽器是多線程請求資源,因此從下圖能夠看出,這裏的順序不必定是代碼中的順序。
瀏覽器在請求靜態資源時(在未過時的狀況下),向服務器發起一個http請求(詢問自從上一次修改時間到如今有沒有對資源進行修改),若是服務器端返回304狀態碼,(告訴服務器端沒有修改),那麼瀏覽器會直接讀取本地的該資源文件。
詳細的瀏覽器工做原理參考:http://kb.cnblogs.com/page/129756/
最後瀏覽器使用本身內部的工做機制,把請求到的靜態資源和html代碼進行渲染,以後呈現給用戶。
至此,一次完整的http請求事務宣告完成。
參考:http://www.360doc.com/content/17/0427/09/35497398_649008108.shtml