1、輸入地址
當我們開始在瀏覽器中輸入網址的時候,瀏覽器其實就已經在智能的匹配可能得 url 了,他會從歷史記錄,書簽等地方,找到已經輸入的字符串可能對應的 url,然后給出智能提示,讓你可以補全url地址。對于?google的chrome 的瀏覽器,他甚至會直接從緩存中把網頁展示出來,就是說,你還沒有按下 enter,頁面就出來了。
2、瀏覽器查找域名的 IP 地址
請求一旦發起,瀏覽器首先要做的事情就是解析這個域名,一般來說,瀏覽器會首先查看本地硬盤的 hosts 文件,看看其中有沒有和這個域名對應的規則,如果有的話就直接使用 hosts 文件里面的 ip 地址。
如果在本地的 hosts 文件沒有能夠找到對應的 ip 地址,瀏覽器會發出一個 DNS請求到本地DNS服務器 。
3、瀏覽器向 web 服務器發送一個 HTTP 請求
拿到域名對應的IP地址之后,瀏覽器會以一個隨機端口(1024<端口<65535)作為客戶端端口向服務器的WEB程序(常用的有httpd,nginx等)80端口發起TCP的連接請求。
在發出請求后需要通過TCP/IP協議棧的層層協議,具體如下:
應用層
這一層組裝http協議,格式化數據
瀏覽器就開始打包本次請求,這里根據傳輸數據加密與否分為 HTTP 請求和 HTTPS 請求,使用的分別是 HTTP 協議和 HTTPS 協議,無論使用哪種協議,都要封裝請求頭和請求參數,以便服務器返回相應的響應。
DNS、HTTP、HTTPS 所在的層是應用層,經過應用層封裝后,瀏覽器將應用層的包交個下一層去完成,這個過程通過 socket 編程來實現。
傳輸層
這一層組裝TCP協議,添加連接客戶端與服務端的端口信息
傳輸層有兩種協議,一種是無連接的 UDP 協議,一種是面向連接的 TCP 協議,UDP 無需建立連接即可通信,但是不可靠,可能會丟包,TCP 需要三次握手建立連接,能夠保證數據包達到目的地,但是有額外的開銷,性能和速度不如 UDP。具體使用哪個協議,需要根據具體需求來定。
對于 HTTP/HTTPS 請求來說,都是基于 TCP 協議的可靠連接,TCP 協議有兩個端口,一個是瀏覽器監聽的端口(監聽服務器響應),一個是服務器監聽的端口(監聽客戶端請求,對于 HTTP 請求,通常是 80 端口,對于 HTTPS 請求,通常是 443 端口)。在傳輸層,會將這兩個端口封裝到TCP協議頭中,以供操作系統根據端口來判斷,將包發送到服務器的那個進程。
網絡層
這一層組裝IP協議,添加本地和目標機器的IP地址
傳輸層封裝完成后,瀏覽器將包交給操作系統的網絡層,網絡層的協議是 IP 協議,在這一層,會給傳輸層傳遞過來的包加上 IP 頭,其中包含源 IP 地址(瀏覽器所在機器)、目標 IP 地址(服務器所在機器)等信息。
操作系統知道目標機器 IP 地址后,就開始根據它來尋找目標機器,通過子網掩碼對IP地址與運算得出網絡地址,如果是本機局域網內的機器,網絡地址必定相同,如果是局域網之外的機器,則通過ARP協議獲取對應目標機器的MAC地址(網卡標識),如果不是局域網之外的機器,則通過網關和路由找到對應目標機器所在的局域網,然后再通過ARP協議獲取對應目標機器的MAC地址。
鏈路層
這一層組裝以太網協議,添加MAC 地址添加到 MAC 頭中
因為以太網協議最長為1500個字節,而IP協議總長度可以達到65535個字節,所以就需要以字節為單位對 0 和 1 進行分組,并且要標識好每一組電信號的信息特征,然后按照分組的順序依次發送,以太網規定一組電信號就是一個數據包,一個數據包被稱為一幀,經由網卡發出。
注:使用網卡(NIC)的情況下,MAC地址會被燒到ROM中,任何一張網卡的MAC地址都是全球唯一的。有人可能會問,有了IP地址為什么還要MAC地址?MAC地址就相當于你的身份證號,一旦出生就寫死了,一輩子都不會變,而且具有全局唯一性。IP地址可以動態分配,不能保證全局唯一,只能保證局域網內唯一,相當于你的居住地址,可能過段時間就會變。 網關收到包以后,會根據自己的知識判斷下一步怎么走,網關往往是一個路由器,到某個目標 IP 地址怎么走,有一個路由表。網絡請求包往往需要經過多個網關的跳轉,才能達到最終的目標機器。
4、服務器的永久重定向響應
服務器給瀏覽器響應一個301永久重定向響應,這樣瀏覽器就會訪問“http://www.google.com/” 而非“http://google.com/”。
為什么服務器一定要重定向而不是直接發送用戶想看的網頁內容呢?其中一個原因跟搜索引擎排名有關。如果一個頁面有兩個地址,就像http://www.yy.com/和http://yy.com/,搜索引擎會認為它們是兩個網站,結果造成每個搜索鏈接都減少從而降低排名。而搜索引擎知道301永久重定向是什么意思,這樣就會把訪問帶www的和不帶www的地址歸到同一個網站排名下。還有就是用不同的地址會造成緩存友好性變差,當一個頁面有好幾個名字時,它可能會在緩存里出現好幾次。
擴展知識
1)301和302的區別。
301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼后會自動跳轉到一個新的URL地址,這個地址可以從響應的Location首部中獲取(用戶看到的效果就是他輸入的地址A瞬間變成了另一個地址B)——這是它們的共同點。
他們的不同在于。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換為重定向之后的網址;
302表示舊地址A的資源還在(仍然可以訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。?SEO302好于301
2)重定向原因:
(1)網站調整(如改變網頁目錄結構);
(2)網頁被移到一個新地址;
(3)網頁擴展名改變(如應用需要把.php改成.Html或.shtml)。
這種情況下,如果不做重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶得到一個404頁面錯誤信息,訪問流量白白喪失;再者某些注冊了多個域名的網站,也需要通過重定向讓訪問這些域名的用戶自動跳轉到主站點等。
3)什么時候進行301或者302跳轉呢?
?當一個網站或者網頁24—48小時內臨時移動到一個新的位置,這時候就要進行302跳轉,而使用301跳轉的場景就是之前的網站因為某種原因需要移除掉,然后要到新的地址訪問,是永久性的。
清晰明確而言:使用301跳轉的大概場景如下:
1、域名到期不想續費(或者發現了更適合網站的域名),想換個域名。
2、在搜索引擎的搜索結果中出現了不帶www的域名,而帶www的域名卻沒有收錄,這個時候可以用301重定向來告訴搜索引擎我們目標的域名是哪一個。
3、空間服務器不穩定,換空間的時候。
5、瀏覽器跟蹤重定向地址
瀏覽器知道了 "http://www.google.com/"才是要訪問的正確地址,所以它會發送另一個http請求。這里沒有啥好說的
6、服務器處理請求并響應
目標服務器網卡接收到數據包,發現與網絡請求包的 MAC 地址對上了,取下MAC頭,將包傳遞給上一層網絡層,發現 IP 也對上了,就取下 IP 頭,然后交給傳輸層。
在傳輸層里,對于收到的每一個包,都要回復包收到了,這個回復不是此次請求的響應,僅僅是回復包已收到而已,這個回復會沿著包的來路回去。如果過了一段時間(超時時間),客戶端還是沒有收到來自服務器的回復,會重新發送這個包,直到收到回復為止。同樣,這個重發也不是重新發起上面那個客戶端請求,而是傳輸層將同一個請求反復重試,對用戶來說,只有一次請求。
回到目標服務器,當網絡包到達傳輸層后,TCP頭中有一個服務器監聽端口號,通過這個端口號,可以找到網站正在監聽的端口,即 Nginx 中配置的 80/443 端口,端口對上之后,取下 TCP 頭,將網絡包交給應用層,開始對 HTTP/HTTPS 請求進行處理。
如果是前端資源的話,直接通過 Nginx 進行響應,如果是 PHP 動態請求的話,再由 Nginx 將請求轉發給后臺運行的 PHP-FPM 進程進行處理。當然如果 Nginx 做了負載均衡,以及后端服務是分布式系統或者提供了微服務的化(涉及到RPC遠程調用),還有更加復雜的處理邏輯。
當后臺服務處理完成后,就會返回一個 HTTPS 的響應包,告知用戶請求成功,并返回響應內容,同樣這個網絡響應包和請求包一樣,自上而下經過層層打包,順著來路經過層層「關卡」(網關),回到發起請求的客戶端,然后再經過自下而上的處理,最終將數據返回到客戶端瀏覽器。
7、瀏覽器顯示 HTML
在瀏覽器沒有完整接受全部HTML文檔時,它就已經開始顯示這個頁面了,瀏覽器是如何把頁面呈現在屏幕上的呢?不同瀏覽器可能解析的過程不太一樣,這里我們只介紹webkit的渲染過程,下圖對應的就是WebKit渲染的過程,這個過程包括:、
瀏覽器在解析html文件時,會”自上而下“加載,并在加載過程中進行解析渲染。在解析過程中,如果遇到請求外部資源時,如圖片、外鏈的CSS、iconfont等,請求過程是異步的,并不會影響html文檔進行加載。
解析過程中,瀏覽器首先會解析HTML文件構建DOM樹,然后解析CSS文件構建渲染樹,等到渲染樹構建完成后,瀏覽器開始布局渲染樹并將其繪制到屏幕上。這個過程比較復雜,涉及到兩個概念: reflow(回流)和repain(重繪)。
DOM節點中的各個元素都是以盒模型的形式存在,這些都需要瀏覽器去計算其位置和大小等,這個過程稱為relow;當盒模型的位置,大小以及其他屬性,如顏色,字體,等確定下來之后,瀏覽器便開始繪制內容,這個過程稱為repain。
頁面在首次加載時必然會經歷reflow和repain。reflow和repain過程是非常消耗性能的,尤其是在移動設備上,它會破壞用戶體驗,有時會造成頁面卡頓。所以我們應該盡可能少的減少reflow和repain。
當文檔加載過程中遇到js文件,html文檔會掛起渲染(加載解析渲染同步)的線程,不僅要等待文檔中js文件加載完畢,還要等待解析執行完畢,才可以恢復html文檔的渲染線程。因為JS有可能會修改DOM,最為經典的document.write,這意味著,在JS執行完成前,后續所有資源的下載可能是沒有必要的,這是js阻塞后續資源下載的根本原因。所以我明平時的代碼中,js是放在html文檔末尾的。
JS的解析是由瀏覽器中的JS解析引擎完成的,比如谷歌的是V8。JS是單線程運行,也就是說,在同一個時間內只能做一件事,所有的任務都需要排隊,前一個任務結束,后一個任務才能開始。但是又存在某些任務比較耗時,如IO讀寫等,所以需要一種機制可以先執行排在后面的任務,這就是:同步任務(synchronous)和異步任務(asynchronous)。
JS的執行機制就可以看做是一個主線程加上一個任務隊列(task queue)。同步任務就是放在主線程上執行的任務,異步任務是放在任務隊列中的任務。所有的同步任務在主線程上執行,形成一個執行棧;異步任務有了運行結果就會在任務隊列中放置一個事件;腳本運行時先依次運行執行棧,然后會從任務隊列里提取事件,運行任務隊列中的任務,這個過程是不斷重復的,所以又叫做事件循環(Event loop)。
在瀏覽器顯示HTML時,它會注意到需要獲取其他地址內容的標簽。這時,瀏覽器會發送一個獲取請求來重新獲得這些文件。比如我要獲取外圖片,CSS,JS文件等,類似于下面的鏈接:
圖片:http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif
CSS式樣表:http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css
JavaScript 文件:http://static.ak.fbcdn.net/rsrc.php/zEMOA/hash/c8yzb6ub.js
這些地址都要經歷一個和HTML讀取類似的過程。所以瀏覽器會在DNS中查找這些域名,發送請求,重定向等等...
不像動態頁面,靜態文件會允許瀏覽器對其進行緩存。有的文件可能會不需要與服務器通訊,而從緩存中直接讀取,或者可以放到CDN中。
已上便是從輸入URL到頁面展示到底發生的過程。