作者 |?peach
來源 | https://juejin.cn/post/6896844956284125191
這個(gè)問題是一個(gè)非常普遍且經(jīng)典的問題,一個(gè)合格的web程序員必須要搞懂的問題栖榨!
詳解
解析url
瀏覽器通過地址欄捕獲到url地址之后靡挥,首先對url地址進(jìn)行解析纵柿。url的解析如下圖所示:
一個(gè)完整的url,包含上述幾部分骗绕,協(xié)議部分一般都是 http或者h(yuǎn)ttps藐窄。域名部分可以是 一段域名例如:baidu.com 也可以是 ip地址,域名最后也會被解析為ip地址酬土。
該ip地址的作用就是在互聯(lián)網(wǎng)中確定服務(wù)器的位置荆忍,緊接著是端口后,端口號確定的是在服務(wù)器中運(yùn)行的具體的程序撤缴。路徑部分表示的是在該程序中資源的具體標(biāo)識刹枉,查詢參數(shù)作用主要是為了發(fā)送數(shù)據(jù)。
DNS解析
一般域名都需要從運(yùn)營商購買屈呕,因?yàn)閕p地址不方便記憶微宝,域名比較好記。域名都會和ip地址綁定虎眨,那么蟋软,在這里就需要做DNS解析,所謂DNS解析其實(shí)就是嗽桩,根據(jù)域名找到其綁定的 ip地址岳守。
查找的順序如下圖:
DNS的查找過程解析:
瀏覽器會先檢查是否存在緩存,因?yàn)槿绻L問過一次該域名的話碌冶,會把結(jié)果緩存在瀏覽器中湿痢。
操作系統(tǒng)也會有自己的DNS緩存,但在這之前扑庞,會檢查域名是否存在于本地的Hosts文件中譬重。
路由器中也會有自己的緩存。
IPS DNS緩存 就是在客戶端電腦上設(shè)置的首選DNS服務(wù)器罐氨。
在前邊所有的情況下都沒有找到緩存的情況下臀规,會連接互聯(lián)網(wǎng),把請求轉(zhuǎn)發(fā)到互聯(lián)網(wǎng)的根域栅隐。
下圖展示了DNS的一個(gè)查詢過程
TCP連接
確定好目標(biāo)服務(wù)器的ip地址和端口號后以现,就開始和遠(yuǎn)程服務(wù)器建立TCP鏈接。三次我說的過程如下:
發(fā)送方:發(fā)送消息约啊,等待...
接收方:接收消息邑遏,并給發(fā)送方回信,此時(shí)發(fā)送方接收到消息后恰矩,從發(fā)送方的角度就可明白自己的消息是可以發(fā)過去的记盒。但是接收方還不能確定自己的消息是否可以正常發(fā)送。
發(fā)送方:接收到發(fā)送方的回信后外傅,在給接收方發(fā)一個(gè)消息纪吮,此時(shí)從接收方的角度就能明白自己的消息可以可以正常發(fā)送俩檬。
畫成圖如下:
TCP三次握手的好處在于的好處在于,發(fā)送方可以確認(rèn)接收方仍然在線
發(fā)送http請求
http協(xié)議是建立在tcp/ip協(xié)議之上的碾盟,tcp保證連接通暢棚辽,http就可以正常的進(jìn)行請求和響應(yīng)了。首先http請求是一個(gè)無狀態(tài)的請求冰肴,且只能由瀏覽器主動發(fā)起屈藐,服務(wù)器進(jìn)行響應(yīng)。
瀏覽器發(fā)送請求的報(bào)文會攜帶以下信息:
請求路徑
查詢參數(shù)
請求方法
請求頭
請求體
服務(wù)器接收請求
在服務(wù)端會監(jiān)聽瀏覽器端發(fā)送的http請求熙尉,當(dāng)瀏覽器的請求發(fā)出后联逻,服務(wù)端就會接受該請求,并解析出相應(yīng)的信息检痰,選擇對應(yīng)的邏輯進(jìn)行處理(比如:查找對應(yīng)的靜態(tài)頁面包归,保存文件,操作數(shù)據(jù)庫铅歼,轉(zhuǎn)發(fā)....),并將處理的結(jié)果響應(yīng)給瀏覽器端公壤。
node服務(wù)器的一個(gè)簡單例子如下:
consthttp =require('http');// 引入http模塊constserver = http.createServer((req, res) =>{// req保存了瀏覽器攜帶的信息// 解析出req的相關(guān)信息,比如 路徑 請求方法 請求頭 請求體等// 編寫服務(wù)端邏輯處理代碼// 響應(yīng)? ? res.end();})server.listen(3000,()=>console.log('::3000'));// 假設(shè)該程序巡行在 ip地址為 140.143.201.230的服務(wù)器上// 假設(shè) 140.143.201.230 綁定的域名是 www.aabbcc.com// 那么請求地址 可以為? http://www.aabbcc.com:3000/home// 當(dāng)瀏覽器請求 http://www.aabbcc.com:3000/home之后椎椰,會DNS解析到服務(wù)器的ip地址為140.143.201.230厦幅,那么上述http.createServer接收的回調(diào)函數(shù)就會執(zhí)行。
服務(wù)器響應(yīng)
服務(wù)器執(zhí)行完邏輯之后俭识,需要給瀏覽器響應(yīng)內(nèi)容(無論是要從服務(wù)器獲取數(shù)據(jù)慨削,還是在服務(wù)器做了什么操作洞渔,都需要給瀏覽器一個(gè)響應(yīng))
響應(yīng)一般包含以下幾部分
狀態(tài)碼
狀態(tài)文本
響應(yīng)頭
響應(yīng)體
服務(wù)器響應(yīng)的同時(shí)肯定會伴隨著瀏覽器端接收套媚,等瀏覽器端徹底接收完畢之后,TCP就要進(jìn)行4次揮手磁椒,并斷開連接了堤瘤。
TCP鏈接斷開
TCP鏈接的斷開需要經(jīng)過"四次揮手",那么就需要一方主動的釋放另外一方被動的釋放浆熔。大體的過程如下:
瀏覽器端發(fā)消息通知服務(wù)器現(xiàn)在需要斷開(第一次揮手)
服務(wù)器接到要斷開的請求之后本辐,給瀏覽器返回消息,告訴瀏覽器我正在準(zhǔn)備釋放(第二次揮手)
此時(shí)瀏覽器接到消息后正在等待服務(wù)器釋放完成医增,而服務(wù)器正在準(zhǔn)備釋放的過程
當(dāng)服務(wù)器釋放完成后慎皱,再通知瀏覽器我已經(jīng)釋放完成了。(第三次揮手)
瀏覽器接收到服務(wù)器釋放完成的消息后叶骨,再給服務(wù)器發(fā)送消息告訴服務(wù)器我已經(jīng)知道你釋放完成了茫多,服務(wù)器收到消息后,就能確認(rèn)自己釋放完成的消息已經(jīng)通知到了(第四次揮手)
瀏覽器解析資源
當(dāng)瀏覽器接收到服務(wù)器響應(yīng)的資源后忽刽,會對資源進(jìn)行解析天揖。
首先夺欲,查看Response Header,根據(jù)響應(yīng)頭的指示做不同的事情,比如重定向今膊,存儲cookie些阅,解壓gzip,緩存資源等等斑唬。
接下來獲取MIME類型(查看響應(yīng)頭的 Content-Type的值)市埋,根據(jù)不同的資源類型采用不同的解析方式
渲染頁面
一般來說從地址欄輸入地址后,絕大多是情況下響應(yīng)的都是 html文件赖钞,那么就說以說頁面是如何渲染html頁面的腰素,html頁面中一般也會嵌入css,js雪营,圖片等資源弓千。
因此如果解析到這些資源的時(shí)候,會再次向目標(biāo)服務(wù)器發(fā)起請求献起,那么又會經(jīng)歷從解析url地址開始的各個(gè)步驟洋访。
整個(gè)頁面的加載如下圖所示:
html頁面的加載
首先要知道瀏覽器解析是從上往下一行一行地解析的。
解碼:傳輸回來的其實(shí)都是一些二進(jìn)制字節(jié)數(shù)據(jù)谴餐,瀏覽器需要根據(jù)文件指定編碼(例如UTF-8)轉(zhuǎn)換成字符串姻政,也就是HTML 代碼
預(yù)解析:預(yù)解析做的事情是提前加載資源,減少處理時(shí)間岂嗓,它會識別一些會請求資源的屬性汁展,比如img標(biāo)簽的src屬性,并將這個(gè)請求加到請求隊(duì)列中厌殉。
符號化:符號化是詞法分析的過程食绿,將輸入解析成符號,HTML 符號包括公罕,開始標(biāo)簽器紧、結(jié)束標(biāo)簽、屬性名和屬性值楼眷。它通過一個(gè)狀態(tài)機(jī)去識別符號的狀態(tài)铲汪,比如遇到<,>狀態(tài)都會產(chǎn)生變化罐柳。
構(gòu)建樹:在上一步符號化中掌腰,解析器獲得這些標(biāo)記,然后以合適的方法創(chuàng)建DOM對象并把這些符號插入到DOM對象中张吉。
瀏覽器的容錯(cuò)機(jī)制:你從來沒有在瀏覽器看過類似”語法無效”的錯(cuò)誤齿梁,這是因?yàn)闉g覽器去糾正錯(cuò)誤的語法,然后繼續(xù)工作芦拿。
CSS解析
一旦瀏覽器下載了 CSS士飒,CSS 解析器就會處理它遇到的任何 CSS查邢,根據(jù)語法規(guī)范解析出所有的 CSS 并進(jìn)行標(biāo)記化,然后我們得到一個(gè)規(guī)則表酵幕。
在匹配一個(gè)節(jié)點(diǎn)對應(yīng)的 CSS 規(guī)則時(shí)扰藕,是按照從右到左的順序的,例如:div p { font-size :14px }會先尋找所有的p標(biāo)簽然后判斷它的父元素是否為div芳撒。
所以我們寫 CSS 時(shí)邓深,盡量用 id 和 class,千萬不要過度層疊笔刹。
javaScript編譯執(zhí)行
大致流程如下:
主要是三個(gè)階段
詞法分析:js腳本加載完畢后芥备,會首先進(jìn)入語法分析階段,它首先會分析代碼塊的語法是否正確舌菜,不正確則拋出“語法錯(cuò)誤”萌壳,停止執(zhí)行。
預(yù)編譯:js有三種運(yùn)行環(huán)境分別是 全局環(huán)境日月,函數(shù)環(huán)境袱瓮,eval。每進(jìn)入一個(gè)不同的運(yùn)行環(huán)境都會創(chuàng)建一個(gè)對應(yīng)的執(zhí)行上下文爱咬,根據(jù)不同的上下文環(huán)境尺借,形成一個(gè)函數(shù)調(diào)用棧,棧底永遠(yuǎn)是全局執(zhí)行上下文精拟,棧頂則永遠(yuǎn)是當(dāng)前執(zhí)行上下文燎斩。
執(zhí)行:js雖然是單線程的,但是實(shí)際參與工作的線程一共有四個(gè):JS引擎線程(主)蜂绎,事件觸發(fā)線程栅表,定時(shí)器觸發(fā)線程,HTTP異步請求線程
總結(jié)
從瀏覽地地址欄輸入地址按下回車荡碾,可以看做是一次請求的發(fā)起谨读,那么必然會經(jīng)歷以下幾個(gè)步驟:
解析url地址
DNS解析
TCP鏈接
發(fā)送http請求
服務(wù)器接收請求
服務(wù)器響應(yīng)
TCP鏈接斷開
瀏覽器解析資源
那么我們需要明白局装,瀏覽器可以發(fā)送請求的方式不止地址欄輸入地址這一種坛吁。比如a標(biāo)簽,img铐尚,link拨脉,script,form表單宣增,ajax玫膀,fetch等等,這些方式都可以發(fā)出http請求爹脾,那么他們都會經(jīng)歷上述的過程帖旨,最終拿到資源箕昭,只是拿到資源的類型不一樣,那么瀏覽器的處理方式也不一樣解阅。