《從 URL 到頁(yè)面展現(xiàn)發(fā)生了什么》這是一個(gè)老生常談的博客題目
老生常談,在編程界里可以理解為【很重要】
以為個(gè)人的理解,前端工程師,說到底就是在研究并實(shí)現(xiàn)《從 URL 到頁(yè)面展現(xiàn)發(fā)生了什么》
我實(shí)在能力有限,對(duì)于這個(gè)題目一直不敢寫,因?yàn)檫@涉及的知識(shí)點(diǎn)太廣了
然而再難也得邁出這一步,因?yàn)槟悴粚懗鰜恚阌肋h(yuǎn)不知道自己的水平到底是多有限
今天是入職的前一天晚上,希望在工作的半年或一年以后,我能對(duì)這個(gè)題目有更加深刻的認(rèn)識(shí)
舉個(gè)例子簡(jiǎn)短回答

為了更好的理解,我們走一遍流程
- 訪問百度主頁(yè)
- 這個(gè)時(shí)候 Client 就是瀏覽器,它發(fā)了一個(gè)請(qǐng)求
- 這個(gè)請(qǐng)求是發(fā)給百度服務(wù)器的,也就是上圖的 Server,但是這個(gè)說法不太準(zhǔn)確,Server 不一定是一個(gè)機(jī)器,也可能是一個(gè)軟件(應(yīng)用程序)
- 接著這個(gè) Server 會(huì)返回 Client 一個(gè)網(wǎng)頁(yè)
- 我們就看到了百度
其實(shí)以上的例子總結(jié)下來就是以下四步么
- 用戶請(qǐng)求遠(yuǎn)程資源
- 瀏覽器查找遠(yuǎn)程資源,打包用戶請(qǐng)求并發(fā)送
- 服務(wù)器根據(jù)用戶請(qǐng)求的資源路徑及附帶參數(shù),配合自身邏輯生成相關(guān)內(nèi)容,發(fā)送給瀏覽器
- 瀏覽器解析結(jié)果,翻譯為直觀方式呈現(xiàn)
好了,回答完畢
標(biāo)準(zhǔn)答案
那么以上步驟具體可以細(xì)化為
- 輸入地址
- 瀏覽器查找域名的 IP 地址
- 瀏覽器向 web 服務(wù)器發(fā)送一個(gè) HTTP 請(qǐng)求
- 服務(wù)器的永久重定向響應(yīng)
- 瀏覽器跟蹤重定向地址
- 服務(wù)器處理請(qǐng)求
- 服務(wù)器返回一個(gè) HTTP 響應(yīng)
- 瀏覽器顯示 HTML
- 瀏覽器發(fā)送請(qǐng)求獲取嵌入在 HTML 中的資源(如圖片、音頻、視頻、CSS、JS等等)
好了,你對(duì)這一系列過程有一個(gè)大體的概念了,接下來細(xì)說每一個(gè)步驟
輸入地址
當(dāng)我們開始在瀏覽器中輸入網(wǎng)址的時(shí)候,瀏覽器其實(shí)就已經(jīng)在智能的匹配可能得 url 了,他會(huì)從歷史記錄,書簽等地方,找到已經(jīng)輸入的字符串可能對(duì)應(yīng)的 url,然后給出智能提示,讓你可以補(bǔ)全url地址。對(duì)于 google 的 chrome 的瀏覽器,他甚至?xí)苯訌木彺嬷邪丫W(wǎng)頁(yè)展示出來,就是說,你還沒有按下 enter,頁(yè)面就出來了。
厲害了
瀏覽器查找域名的 IP 地址
URL 到服務(wù)器逐級(jí)
- 一個(gè)頁(yè)面訪問的本質(zhì)是我們希望通過一個(gè)路徑找到相應(yīng)的資源
- 路徑就是我們的 URL,資源是服務(wù)器給我們的請(qǐng)求的響應(yīng)
- 首先我們需要找到網(wǎng)絡(luò)上的服務(wù)器才能找到機(jī)器上的資源,網(wǎng)絡(luò)主機(jī)的定位靠的是 IP 地址
域名到IP
IP(Internet Protocol)
: 互聯(lián)網(wǎng)中設(shè)備間進(jìn)行通信都要遵從的一種協(xié)議,它規(guī)定了每臺(tái)設(shè)備都要有且唯一的 IP 地址,用來標(biāo)識(shí)自己在互聯(lián)網(wǎng)中的地址。格式通常為 http://XXX.XXX.XXX.XXX,不同網(wǎng)段下 IP 地址的范圍也不同。如有興趣者,請(qǐng)自行百度。
域名(Domain Name)
: 由于IP協(xié)議規(guī)定的純數(shù)字 IP 地址在日常中難以記憶,因此人們便產(chǎn)生使用更加常見,好記的字符標(biāo)識(shí)設(shè)備的地址,域名應(yīng)運(yùn)而生。一個(gè)域名就是一個(gè)更加容易記憶的目標(biāo)主機(jī)的地址標(biāo)識(shí)符。例如:百度的域名就為百度一下,你就知道,實(shí)際對(duì)應(yīng)的IP地址為 119.75.217.109
DNS(Domain Name System)
: 互聯(lián)網(wǎng)中實(shí)際定位設(shè)備時(shí)還是使用 IP 地址來定位,因此產(chǎn)生了 DNS,一種專門用來將域名轉(zhuǎn)換為 IP 地址的協(xié)議,提供該協(xié)議服務(wù)的服務(wù)器就叫 DNS 服務(wù)器。
總結(jié)一下
- 為什么用域名不用IP
- 因?yàn)?IP 有點(diǎn)反人類的記憶思維
- 域名和 IP 對(duì)應(yīng) DNS (Domain Name System)
實(shí)際上DNS就是一組鍵值對(duì),鍵名就是域名,值就是IP地址
DNS解析
輸入了一個(gè)域名,你得靠 DNS 解析出一個(gè)相應(yīng)的 IP 地址吧
- 瀏覽器緩存:如果之前訪問過該主機(jī),(不是URL指定的資源),瀏覽器會(huì)緩存DNS一段時(shí)間,這樣就可以直接使用瀏覽器緩存的DNS,至于一段時(shí)間是多久沒要求,瀏覽器自行決定
- 系統(tǒng)緩存:如果瀏覽器緩存里沒有記錄,瀏覽器會(huì)做系統(tǒng)調(diào)用,獲取系統(tǒng)中的緩存記錄
- 路由器緩存:如果系統(tǒng)緩存同樣沒有命中,那就需要查詢路由器緩存了
- ISP(互聯(lián)網(wǎng)服務(wù)提供商,例如電信,移動(dòng))的 DNS 緩存:路由器緩存未命中會(huì)查詢 ISP(Internet Service Provider),一般域名在這里都可以找到了
- 遞歸搜索:我們使用的 ISP 的 DNS 記錄里面如果還沒有的話,那么就會(huì)從頂級(jí)域名服務(wù)器的根域名服務(wù)器開始遞歸查詢,這個(gè)肯定會(huì)查到了

第三者
實(shí)際上瀏覽器充當(dāng)了我們要找到的 IP 地址的第三者,類似中介
可以用以下代碼來看瀏覽器的版本
window.navigator.userAgent
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
瀏覽器向 web 服務(wù)器發(fā)送一個(gè) HTTP 請(qǐng)求
打包 HTTP 請(qǐng)求

圖中的請(qǐng)求是什么,僅僅是輸入的 URL 么
當(dāng)然不是,請(qǐng)求是一段報(bào)文,包括但不僅僅是 URL
那么請(qǐng)求(request)包含什么呢
- 請(qǐng)求行
- 請(qǐng)求頭
- 空行
- 消息體
請(qǐng)求又分為兩類
- GET 請(qǐng)求
- POST 請(qǐng)求
GET 請(qǐng)求
GET / HTTP/1.1 // 請(qǐng)求行,下面一直到空行之上都是請(qǐng)求頭
Host: www.baidu.com
Accept: text/html
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4
Cookie: BAIDUID=5A056AFFCD3D7072D17933F3750CAB0B:FG=1;
// 空行
// 如果是 GET,那么一般消息體是空的
POST 請(qǐng)求
POST /login/email HTTP/1.1 // 請(qǐng)求行,下面一直到空行之上都是請(qǐng)求頭
Host: www.zhihu.com
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8 // 描述消息體
Content-Length: 119
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9
Cookie: _xsrf=e0f0996099f0c4e3e0157d92d65dfe23;
// 空行
password=zhihu&captcha=mrah&remember_me=true&email=huayiqishi%40qq.com // 消息體
創(chuàng)建 TCP 連接
- 一般瀏覽器都是通過使用的 TCP 協(xié)議,UDP 不可靠,所以瀏覽器得到的 response 要么是全的,要么得不到
- 瀏覽器打包請(qǐng)求自然也是打包的 HTTP 報(bào)文
- 那么為什么有時(shí)候我們看到的頁(yè)面是殘缺不全的呢(因?yàn)槭琴Y源下載失敗了而不是 response 這個(gè)文本有殘缺)
瀏覽器發(fā)送請(qǐng)求的方法
- get
- head
- post
- trace
- options
- put(往服務(wù)器上面放置一些東西)
- delete(往服務(wù)器上刪除一些東西)
一般的瀏覽器只能發(fā)起 GET 或者 POST 請(qǐng)求
服務(wù)器的永久重定向響應(yīng)
服務(wù)器給瀏覽器響應(yīng)一個(gè)301永久重定向響應(yīng),這樣瀏覽器就會(huì)訪問 http://www.google.com/ 而非 http://google.com/。
為什么服務(wù)器一定要重定向而不是直接發(fā)送用戶想看的網(wǎng)頁(yè)內(nèi)容呢?其中一個(gè)原因跟搜索引擎排名有關(guān)。如果一個(gè)頁(yè)面有兩個(gè)地址,就像 http://www.yy.com/ 和 http://yy.com/,搜索引擎會(huì)認(rèn)為它們是兩個(gè)網(wǎng)站,結(jié)果造成每個(gè)搜索鏈接都減少?gòu)亩档团琶?。而搜索引擎知?01永久重定向是什么意思,這樣就會(huì)把訪問帶 www 的和不帶 www 的地址歸到同一個(gè)網(wǎng)站排名下。還有就是用不同的地址會(huì)造成緩存友好性變差,當(dāng)一個(gè)頁(yè)面有好幾個(gè)名字時(shí),它可能會(huì)在緩存里出現(xiàn)好幾次。
301和302的區(qū)別
301和302狀態(tài)碼都表示重定向,就是說瀏覽器在拿到服務(wù)器返回的這個(gè)狀態(tài)碼后會(huì)自動(dòng)跳轉(zhuǎn)到一個(gè)新的 URL 地址,這個(gè)地址可以從響應(yīng)的 Location 首部中獲?。ㄓ脩艨吹降男Ч褪撬斎氲牡刂?A 瞬間變成了另一個(gè)地址 B)——這是它們的共同點(diǎn)。
他們的不同在于
- 301表示舊地址 A 的資源已經(jīng)被永久地移除了(這個(gè)資源不可訪問了),搜索引擎在抓取新內(nèi)容的同時(shí)也將舊的網(wǎng)址交換為重定向之后的網(wǎng)址;
- 302表示舊地址 A 的資源還在(仍然可以訪問),這個(gè)重定向只是臨時(shí)地從舊地址 A 跳轉(zhuǎn)到地址 B,搜索引擎會(huì)抓取新的內(nèi)容而保存舊的網(wǎng)址。 SEO 302好于301
重定向原因
- 網(wǎng)站調(diào)整(如改變網(wǎng)頁(yè)目錄結(jié)構(gòu))
- 網(wǎng)頁(yè)被移到一個(gè)新地址
- 網(wǎng)頁(yè)擴(kuò)展名改變(如應(yīng)用需要把.php改成.Html或.shtml)
這種情況下,如果不做重定向,則用戶收藏夾或搜索引擎數(shù)據(jù)庫(kù)中舊地址只能讓訪問客戶得到一個(gè)404頁(yè)面錯(cuò)誤信息,訪問流量白白喪失;再者某些注冊(cè)了多個(gè)域名的網(wǎng)站,也需要通過重定向讓訪問這些域名的用戶自動(dòng)跳轉(zhuǎn)到主站點(diǎn)等。
什么時(shí)候進(jìn)行301或者302跳轉(zhuǎn)
當(dāng)一個(gè)網(wǎng)站或者網(wǎng)頁(yè)24—48小時(shí)內(nèi)臨時(shí)移動(dòng)到一個(gè)新的位置,這時(shí)候就要進(jìn)行302跳轉(zhuǎn),而使用301跳轉(zhuǎn)的場(chǎng)景就是之前的網(wǎng)站因?yàn)槟撤N原因需要移除掉,然后要到新的地址訪問,是永久性的。
清晰明確而言,使用301跳轉(zhuǎn)的大概場(chǎng)景如下:
- 域名到期不想續(xù)費(fèi)(或者發(fā)現(xiàn)了更適合網(wǎng)站的域名),想換個(gè)域名。
- 在搜索引擎的搜索結(jié)果中出現(xiàn)了不帶www的域名,而帶www的域名卻沒有收錄,這個(gè)時(shí)候可以用301重定向來告訴搜索引擎我們目標(biāo)的域名是哪一個(gè)。
- 空間服務(wù)器不穩(wěn)定,換空間的時(shí)候。
瀏覽器跟蹤重定向地址
現(xiàn)在瀏覽器知道了 "http://www.google.com/"才是要訪問的正確地址,所以它會(huì)發(fā)送另一個(gè)http請(qǐng)求。這里沒有啥好說的
服務(wù)器處理請(qǐng)求
相關(guān)進(jìn)程處理請(qǐng)求
主機(jī)運(yùn)行多個(gè)程序,那個(gè)來處理HTTP請(qǐng)求呢
- http: 80
- https: 443
- ftp: 21
- ssh: 22
服務(wù)器
- 物理主機(jī)
- web server
服務(wù)器返回一個(gè) HTTP 響應(yīng)
服務(wù)器響應(yīng)請(qǐng)求
哪些內(nèi)容影響服務(wù)器結(jié)果呢
- 請(qǐng)求方法
- 路徑
- query string
- cookkie
- 服務(wù)器配置
- 動(dòng)態(tài)語(yǔ)言代碼邏輯
服務(wù)器響應(yīng)內(nèi)容
- 狀態(tài)行
- 響應(yīng)頭
- 響應(yīng)正文
1. 狀態(tài)行
- 協(xié)議版本:是用http1.0還是其他版本
- 狀態(tài)描述:狀態(tài)描述給出了關(guān)于狀態(tài)代碼的簡(jiǎn)短的文字描述。比如狀態(tài)代碼為200時(shí)的描述為 ok
- 狀態(tài)代碼:狀態(tài)代碼由三位數(shù)字組成,第一個(gè)數(shù)字定義了響應(yīng)的類別,且有五種可能取值
例如:HTTP/1.1 200 OK
2. 響應(yīng)頭
響應(yīng)頭部:由關(guān)鍵字/值對(duì)組成,每行一對(duì),關(guān)鍵字和值用英文冒號(hào)":"分隔,典型的響應(yīng)頭有:

3. 響應(yīng)正文
包含著我們需要的一些具體信息,比如cookie,html,image,后端返回的請(qǐng)求數(shù)據(jù)等等。這里需要注意,響應(yīng)正文和響應(yīng)頭之間有一行空格,表示響應(yīng)頭的信息到空格為止,下圖是fiddler抓到的請(qǐng)求正文,紅色框中的響應(yīng)正文:

瀏覽器顯示 HTML
渲染頁(yè)面
- 瀏覽器下載的順序是從上到下,渲染的順序也是從上到下,下載和渲染同時(shí)進(jìn)行
- 解析 HTML 生成 DOM 樹
- 解析 HTML 中的 CSS,生成渲染樹
- 解析 JavaScript,解析到的時(shí)候執(zhí)行
瀏覽器是如何把頁(yè)面呈現(xiàn)在屏幕上的呢?不同瀏覽器可能解析的過程不太一樣,這里我們只介紹webkit的渲染過程,下圖對(duì)應(yīng)的就是WebKit渲染的過程,這個(gè)過程包括:
解析html以構(gòu)建dom樹 -> 構(gòu)建render樹 -> 布局render樹 -> 繪制render樹

瀏覽器在解析html文件時(shí),會(huì)”自上而下“加載,并在加載過程中進(jìn)行解析渲染。在解析過程中,如果遇到請(qǐng)求外部資源時(shí),如圖片、外鏈的 CSS、iconfont 等,請(qǐng)求過程是異步的,并不會(huì)影響 html 文檔進(jìn)行加載。
解析過程中,瀏覽器首先會(huì)解析 HTML 文件構(gòu)建 DOM 樹,然后解析 CSS 文件構(gòu)建渲染樹,等到渲染樹構(gòu)建完成后,瀏覽器開始布局渲染樹并將其繪制到屏幕上。這個(gè)過程比較復(fù)雜,涉及到兩個(gè)概念: reflow(回流)和 repain(重繪)。
DOM 節(jié)點(diǎn)中的各個(gè)元素都是以盒模型的形式存在,這些都需要瀏覽器去計(jì)算其位置和大小等,這個(gè)過程稱為 relow,當(dāng)盒模型的位置,大小以及其他屬性,如顏色、字體等確定下來之后,瀏覽器便開始繪制內(nèi)容,這個(gè)過程稱為 repain。
頁(yè)面在首次加載時(shí)必然會(huì)經(jīng)歷 reflow 和 repain。reflow 和 repain 過程是非常消耗性能的,尤其是在移動(dòng)設(shè)備上,它會(huì)破壞用戶體驗(yàn),有時(shí)會(huì)造成頁(yè)面卡頓。所以我們應(yīng)該盡可能少的減少 reflow 和 repain。
關(guān)聯(lián)資源處理
- 在展現(xiàn)到頁(yè)面的某一部分時(shí),即上面的所有部分都已經(jīng)下載完成
- 并不是說所有相關(guān)聯(lián)的元素都已經(jīng)下載完,圖片,視頻等元素需要另外并行下載
- 同一個(gè)域名下并行下載數(shù)量有限制
JS 和 AJAX
- JS 不能并行的下載和解析,采用阻塞的方式,當(dāng)頁(yè)面引用了 JS 的時(shí)候?yàn)g覽器發(fā)送請(qǐng)求后會(huì)一直阻塞直到得到響應(yīng)
- 因?yàn)闉g覽器需要1個(gè)穩(wěn)定的 DOM 樹結(jié)構(gòu),而 JS 中很有可能有代碼直接改變了 DOM 樹結(jié)構(gòu),瀏覽器為了防止出現(xiàn) JS 修改 DOM 樹,需要重新構(gòu)建 DOM 樹的情況,所以就會(huì)阻塞其他的下載和呈現(xiàn)
- 遇到 AJAX 后執(zhí)行,然后進(jìn)行下面的步驟,AJAX 拿到結(jié)果后再執(zhí)行 AJAX 回調(diào)函數(shù)
CSS
- 樣式表在下載完成后,將和以前下載的所有樣式表一起進(jìn)行解析,解析完成后,將對(duì)此前所有元素(含以前已經(jīng)渲染的)重新進(jìn)行渲染
- JS,CSS 中如果有重定義,后定義將覆蓋之前的定義,而不會(huì)報(bào)錯(cuò)
直接使用本地緩存
- 服務(wù)器發(fā)給瀏覽器的文件中會(huì)帶有 Expires 或 Cache-Control 說明文件什么時(shí)候失效
- 在有效期內(nèi)的話瀏覽器直接使用本地文件,不發(fā)請(qǐng)求
服務(wù)器驗(yàn)證
- 服務(wù)器響應(yīng)中會(huì)帶有文件的最后修改時(shí)間或 Etag
- 瀏覽器發(fā)送重復(fù)請(qǐng)求會(huì)帶上這些信息,如果服務(wù)器判斷沒有變化,發(fā)送304狀態(tài)碼,讓瀏覽器使用本地緩存
好了,從 URL 到頁(yè)面展現(xiàn)大概就是這個(gè)樣子的
當(dāng)然了,作為勵(lì)志做一名號(hào)前端的我們,知道這些是遠(yuǎn)遠(yuǎn)不夠的,請(qǐng)把以上的每一個(gè)點(diǎn)都細(xì)化成博客,我相信功力會(huì)大增的
學(xué)點(diǎn)單詞
- preserve
英 [pr??z?:v] 美 [pr??z?rv]
vt. 保護(hù); 保持,保存; 腌制食物; 防腐處理;
vi. 保鮮; 保持原狀; 做蜜餞; 禁獵;
n. 蜜餞; 防護(hù)用品; 禁獵地; 獨(dú)占的事物(或范圍); - cache
英 [k??] 美 [k??]
n. 藏物處; 隱藏處; 藏匿的珍寶; <電腦>快速緩沖貯存區(qū);
vt. 貯藏;
vi. 躲藏;
參考文章
(完)
文檔信息
- 自由轉(zhuǎn)載-非商用-非衍生-保持署名
- 發(fā)表日期:2017年6月4日