對于前端來說,HTML 都是最基礎(chǔ)的內(nèi)容。
今天,我們來了解一下 HTML 和網(wǎng)頁有什么關(guān)系,以及與 DOM 有什么不同。通過本講內(nèi)容,你將掌握瀏覽器是怎么處理 HTML 內(nèi)容的,以及在這個過程中我們可以進(jìn)行怎樣的處理來提升網(wǎng)頁的性能,從而提升用戶的體驗。
不知你是否有過這樣的體驗:當(dāng)打開某個瀏覽器的時候,發(fā)現(xiàn)一直在轉(zhuǎn)圈,或者等了好長時間才打開頁面……
此時的你,會選擇關(guān)掉頁面還是耐心等待呢?
這一現(xiàn)象,除了網(wǎng)絡(luò)不穩(wěn)定、網(wǎng)速過慢等原因,大多數(shù)都是由于頁面設(shè)計不合理導(dǎo)致加載時間過長導(dǎo)致的。
我們都知道,頁面是用 HTML/CSS/JavaScript 來編寫的。
HTML由一系列的元素組成,通常稱為HTML元素。HTML 元素通常被用來定義一個網(wǎng)頁結(jié)構(gòu),基本上所有網(wǎng)頁都是這樣的 HTML 結(jié)構(gòu):
<html>
<head></head>
<body></body>
</html>
其中:
HTML 中的元素特別多,其中還包括可用于 Web Components 的自定義元素。
前面我們提到頁面 HTML 結(jié)構(gòu)不合理可能會導(dǎo)致頁面響應(yīng)慢,這個過程很多時候體現(xiàn)在<script>和<style>元素的設(shè)計上,它們會影響頁面加載過程中對 Javascript 和 CSS 代碼的處理。
因此,如果想要提升頁面的加載速度,就需要了解瀏覽器頁面的加載過程是怎樣的,從根本上來解決問題。
瀏覽器在加載頁面的時候會用到 GUI 渲染線程和 JavaScript 引擎線程(更詳細(xì)的瀏覽器加載和渲染機制將在第 7 講中介紹)。其中,GUI 渲染線程負(fù)責(zé)渲染瀏覽器界面 HTML 元素,JavaScript 引擎線程主要負(fù)責(zé)處理 JavaScript 腳本程序。
由于 JavaScript 在執(zhí)行過程中還可能會改動界面結(jié)構(gòu)和樣式,因此它們之間被設(shè)計為互斥的關(guān)系。也就是說,當(dāng) JavaScript 引擎執(zhí)行時,GUI 線程會被掛起。
以網(wǎng)易云課堂官網(wǎng)為例,我們來看看網(wǎng)頁加載流程。
(1)當(dāng)我們打開官網(wǎng)的時候,瀏覽器會從服務(wù)器中獲取到 HTML 內(nèi)容。
(2)瀏覽器獲取到 HTML 內(nèi)容后,就開始從上到下解析 HTML 的元素。
(3)<head>元素內(nèi)容會先被解析,此時瀏覽器還沒開始渲染頁面。
我們看到<head>元素里有用于描述頁面元數(shù)據(jù)的<meta>元素,還有一些<link>元素涉及外部資源(如圖片、CSS 樣式等),此時瀏覽器會去獲取這些外部資源。除此之外,我們還能看到<head>元素中還包含著不少的<script>元素,這些<script>元素通過src屬性指向外部資源。
(4)當(dāng)瀏覽器解析到這里時(步驟 3),會暫停解析并下載 JavaScript 腳本。
(5)當(dāng) JavaScript 腳本下載完成后,瀏覽器的控制權(quán)轉(zhuǎn)交給 JavaScript 引擎。當(dāng)腳本執(zhí)行完成后,控制權(quán)會交回給渲染引擎,渲染引擎繼續(xù)往下解析 HTML 頁面。
(6)此時<body>元素內(nèi)容開始被解析,瀏覽器開始渲染頁面。
在這個過程中,我們看到<head>中放置的<script>元素會阻塞頁面的渲染過程:把 JavaScript 放在<head>里,意味著必須把所有 JavaScript 代碼都下載、解析和解釋完成后,才能開始渲染頁面。
到這里,我們就明白了:如果外部腳本加載時間很長(比如一直無法完成下載),就會造成網(wǎng)頁長時間失去響應(yīng),瀏覽器就會呈現(xiàn)“假死”狀態(tài),用戶體驗會變得很糟糕。
因此,對于對性能要求較高、需要快速將內(nèi)容呈現(xiàn)給用戶的網(wǎng)頁,常常會將 JavaScript 腳本放在<body>的最后面。這樣可以避免資源阻塞,頁面得以迅速展示。我們還可以使用defer/async/preload等屬性來標(biāo)記<script>標(biāo)簽,來控制 JavaScript 的加載順序。
百度首頁
對于百度這樣的搜索引擎來說,必須要在最短的時間內(nèi)提供到可用的服務(wù)給用戶,其中就包括搜索框的顯示及可交互,除此之外的內(nèi)容優(yōu)先級會相對較低。
瀏覽器在渲染頁面的過程需要解析 HTML、CSS 以得到 DOM 樹和 CSS 規(guī)則樹,它們結(jié)合后才生成最終的渲染樹并渲染。因此,我們還常常將 CSS 放在<head>里,可用來避免瀏覽器渲染的重復(fù)計算。
我們知道<p>是 HTML 元素,但又常常將<p>這樣一個元素稱為 DOM 節(jié)點,那么 HTML 和 DOM 到底有什么不一樣呢?
根據(jù) MDN 官方描述:文檔對象模型(DOM)是 HTML 和 XML 文檔的編程接口。
也就是說,DOM 是用來操作和描述 HTML 文檔的接口。如果說瀏覽器用 HTML 來描述網(wǎng)頁的結(jié)構(gòu)并渲染,那么使用 DOM 則可以獲取網(wǎng)頁的結(jié)構(gòu)并進(jìn)行操作。一般來說,我們使用 JavaScript 來操作 DOM 接口,從而實現(xiàn)頁面的動態(tài)變化,以及用戶的交互操作。
在開發(fā)過程中,常常用對象的方式來描述某一類事物,用特定的結(jié)構(gòu)集合來描述某些事物的集合。DOM 也一樣,它將 HTML 文檔解析成一個由 DOM 節(jié)點以及包含屬性和方法的相關(guān)對象組成的結(jié)構(gòu)集合。
我們常見的 HTML 元素,在瀏覽器中會被解析成節(jié)點。比如下面這樣的 HTML 內(nèi)容:
<html>
<head>
<title>標(biāo)題</title>
</head>
<body>
<a href='xx.com'>我的超鏈接</a>
<h1>頁面第一標(biāo)題</h1>
</body>
</html>
打開控制臺 Elements 面板,可以看到這樣的 HTML 結(jié)構(gòu),如下圖所示:
在瀏覽器中,上面的 HTML 會被解析成這樣的 DOM 樹,如下圖所示:
我們都知道,對于樹狀結(jié)構(gòu)來說,常常使用parent/child/sibling等方式來描述各個節(jié)點之間的關(guān)系,對于 DOM 樹也不例外。
舉個例子,我們常常會對頁面功能進(jìn)行抽象,并封裝成組件。但不管怎么進(jìn)行整理,頁面最終依然是基于 DOM 的樹狀結(jié)構(gòu),因此組件也是呈樹狀結(jié)構(gòu),組件間的關(guān)系也同樣可以使用parent/child/sibling這樣的方式來描述。同時,現(xiàn)在大多數(shù)應(yīng)用程序同樣以root為根節(jié)點展開,我們進(jìn)行狀態(tài)管理、數(shù)據(jù)管理也常常會呈現(xiàn)出樹狀結(jié)構(gòu)。
我們知道,瀏覽器中各個元素從頁面中接收事件的順序包括事件捕獲階段、目標(biāo)階段、事件冒泡階段。其中,基于事件冒泡機制,我們可以實現(xiàn)將子元素的事件委托給父級元素來進(jìn)行處理,這便是事件委托。
如果我們在每個元素上都進(jìn)行監(jiān)聽的話,則需要綁定三個事件;(假設(shè)頁面上有a,b,c三個兄弟節(jié)點)
function clickEventFunction(e) {
console.log(e.target === this); // logs `true`
// 這里可以用 this 獲取當(dāng)前元素
}
// 元素a,b,c綁定
element2.addEventListener("click", clickEventFunction, false);
element5.addEventListener("click", clickEventFunction, false);
element8.addEventListener("click", clickEventFunction, false);
使用事件委托,可以通過將事件添加到它們的父節(jié)點,而將事件委托給父節(jié)點來觸發(fā)處理函數(shù):
function clickEventFunction(event) {
console.log(e.target === this); // logs `false`
// 獲取被點擊的元素
const eventTarget = event.target;
// 檢查源元素`event.target`是否符合預(yù)期
// 此處控制廣告面板的展示內(nèi)容
}
// 元素1綁定
element1.addEventListener("click", clickEventFunction, false);
這樣能解決什么問題呢?
常見的使用方式主要是上述這種列表結(jié)構(gòu),每個選項都可以進(jìn)行編輯、刪除、添加標(biāo)簽等功能,而把事件委托給父元素,不管我們新增、刪除、更新選項,都不需要手動去綁定和移除事件。
如果在列表數(shù)量內(nèi)容較大的時候,對成千上萬節(jié)點進(jìn)行事件監(jiān)聽,也是不小的性能消耗。使用事件委托的方式,我們可以大量減少瀏覽器對元素的監(jiān)聽,也是在前端性能優(yōu)化中比較簡單和基礎(chǔ)的一個做法。
注意:
我們了解了 HTML 的作用,以及它是如何影響瀏覽器中頁面的加載過程的,同時還介紹了使用 DOM 接口來控制 HTML 的展示和功能邏輯。我們了解了DOM解析事件委托等相關(guān)概念。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>百度一下,你就知道</title>
<style type="text/css">
#img1{
position: relative;
left: 650px;
}
ul li{
float:left;
list-style: none;
padding: 5px;
}
a{
padding: 5px;
text-decoration:none;
}
#baidu{
text-align: center;
}
#input1{
font-size: 30px;
width: 560px;
}
#db{
position:fixed; bottom:0;
}
#div1{
position: absolute;
bottom: 0;
right: 0;
}
#rebang{
font-size: 25px;
position: relative;
left: 610px;
}
ul li div{
display: none;
}
ul li:hover div{
display: block;
}
#C{
font-size: 20px;
float: left;
}
#B{
position: absolute;
margin-left: 260px;
display: none;
}
#A{
font-size: 20px;
width: 1000px;
}
#A:hover #B{
display: block;
}
#D{
font-size: 20px;
float: right;
}
#F{
position: absolute;
display: none;
}
#D:hover #F{
display: block;
}
#G{
height: 50px;
float: right;
}
#H{
background-color: blue;
}
#J{
position: absolute;
right: 800px;
top: 300px;
display: none;
z-index: 2;
}
#G:hover #J{
display: block;
}
#Z{
width: 100px;
height: 30px;
}
#W{
font-size: 22px;
}
</style>
</head>
<body>
<div id="C">
<a href="http://news.baidu.com/" target="_blank">新聞</a>
<a href="https://www.hao123.com/" target="_blank">hao123</a>
<a href="https://map.baidu.com/@12126927,4038819,13z/" target="_blank">地圖</a>
<a href="https://haokan.baidu.com/?sfrom=baidu-top/" target="_blank">視頻</a>
<a href="https://tieba.baidu.com/index.html/" target="_blank">貼吧</a>
<a href="https://xueshu.baidu.com//" target="_blank">學(xué)術(shù)</a>
</div>
<div id="A">
<a href="https://www.baidu.com/more//" target="_blank">更多</a>
<div id="B">
<ul>
<li><a href="https://pan.baidu.com/" target="_blank"><img src="imgs/wangpan.png"></img><br>網(wǎng)盤</a></li>
<li><a href="https://zhidao.baidu.com/" target="_blank"><img src="imgs/zhidao.png"></img><br>知道</a></li>
<li><a href="https://baike.baidu.com/" target="_blank"><img src="imgs/baike.png"></img><br>百科</a></li>
<li><a href="https://image.baidu.com/" target="_blank"><img src="imgs/tupian.png"></img><br>圖片</a></li>
</ul>
<ul>
<li><a href="https://baobao.baidu.com/" target="_blank"><img src="imgs/baobao.png"></img><br>寶寶</a></li>
<li><a href="https://wenku.baidu.com/" target="_blank"><img src="imgs/wenku.png"></img><br>文庫</a></li>
<li><a href="https://jingyan.baidu.com/" target="_blank"><img src="imgs/jingyan.png"></img><br>經(jīng)驗</a></li>
<li><a href="http://music.taihe.com/" target="_blank"><img src="imgs/yinyue.png"></img><br>音樂</a></li>
</ul>
</div>
</div>
<div id="G">
<a href="#"><input type="button" value="登錄"></input></a>
<div id="J">
<img src="imgs/JJJ.png" >
</div>
</div>
<div id="D">
<a href="#">設(shè)置</a>
<div id="F">
<a href="#">搜索設(shè)置</a><br>
<a href="#">高級搜索</a><br>
<a href="#">關(guān)閉預(yù)測</a><br>
<a href="#">隱私設(shè)置</a><br>
</div>
</div>
<div id="img1">
<img src="imgs/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png">
</div>
<div id="baidu">
<a href="#"><input id="input1" type="text" id="" value="" /><input id="Z" type="button" value="百度一下" /></a>
</div>
<div id="rebang">
<a href="http://top.baidu.com/?fr=mhd_card">百度熱榜</a>
</div>
<div id="resou" align="center">
<table id="W" border="0" cellspacing="5" cellpadding="25">
<tr>
<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E7%89%B9%E6%9C%97%E6%99%AE%E7%A7%B0NBA%E5%83%8F%E4%B8%80%E4%B8%AA%E6%94%BF%E6%B2%BB%E7%BB%84%E7%BB%87&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">1.特朗普炮轟NBA</a></td>
<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E5%AE%98%E6%96%B9%E8%B0%83%E6%9F%A5%E5%A5%B3%E6%95%99%E5%B8%88%E4%B8%BE%E6%8A%A5%E6%A0%A1%E9%95%BF%E6%80%A7%E9%AA%9A%E6%89%B0&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">4.官方調(diào)查女教師</a></td>
</tr>
<tr>
<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E8%94%A1%E8%8E%89%E4%B8%8D%E5%86%8D%E6%8B%85%E4%BB%BB%E6%AD%A6%E6%B1%89%E5%B8%82%E4%B8%AD%E5%BF%83%E5%8C%BB%E9%99%A2%E4%B9%A6%E8%AE%B0&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">2.蔡麗不再擔(dān)任武漢市醫(yī)院書記</a></td>
<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E9%99%88%E9%98%BF%E5%96%9C%E5%8E%BB%E4%B8%96&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">5.陳阿喜去世</a></td>
</tr>
<tr>
<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E5%85%A8%E7%90%83%E8%BF%9110%E4%BA%BF%E4%BA%BA%E5%8F%97%E7%B2%BE%E7%A5%9E%E5%81%A5%E5%BA%B7%E9%97%AE%E9%A2%98%E5%BD%B1%E5%93%8D&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">3.全球近10億人受精神健康問題影響</a></td>
<td><a href="https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=31%E7%9C%81%E5%8C%BA%E5%B8%82%E6%96%B0%E5%A2%9E%E5%A2%83%E5%A4%96%E8%BE%93%E5%85%A59%E4%BE%8B&rsv_idx=2&rsv_dl=fyb_n_homepage&hisfilter=1">6.31省區(qū)市新增境外輸入9例</a></td>
</tr>
</table>
</div>
<div id="db">
<ul>
<li>設(shè)為首頁</li>
<li>關(guān)于百度</li>
<li>About Baidu</li>
<li>百度營銷</li>
<li>使用百度前必讀</li>
<li>意見反饋</li>
<li>幫助中心</li>
</ul>
</div>
<div id="div1">
<ul>
<li>@2020 Baidu</li>
<li>(京)-經(jīng)營性-2017-0020</li>
<li>京公網(wǎng)安備11000002000001號</li>
<li>京ICP證030173號</li></ul>
</div>
</body>
</html>
新手勿噴!!!
者公眾號:org_yijiaoqian
1.0的HTTP版本,是一種無狀態(tài),無連接的應(yīng)用層協(xié)議。 HTTP1.0規(guī)定瀏覽器和服務(wù)器保持短暫的鏈接。
瀏覽器每次請求都需要與服務(wù)器建立一個TCP連接,服務(wù)器處理完成以后立即斷開TCP連接(無連接),服務(wù)器不跟蹤也每個客戶單,也不記錄過去的請求(無狀態(tài))。
這種無狀態(tài)性可以借助cookie/session機制來做身份認(rèn)證和狀態(tài)記錄。
每次發(fā)送請求,都需要進(jìn)行一次TCP連接,而TCP的連接釋放過程又是比較費事的。這種無連接的特性會使得網(wǎng)絡(luò)的利用率變低。
由于HTTP1.0規(guī)定下一個請求必須在前一個請求響應(yīng)到達(dá)之前才能發(fā)送,假設(shè)前一個請求響應(yīng)一直不到達(dá),那么下一個請求就不發(fā)送,后面的請求就阻塞了。
HTTP1.1繼承了HTTP1.0的簡單,克服了HTTP1.0性能上的問題。
HTTP1.1增加Connection字段,通過設(shè)置Keep-Alive保持HTTP連接不斷卡。避免每次客戶端與服務(wù)器請求都要重復(fù)建立釋放建立TCP連接。提高了網(wǎng)絡(luò)的利用率。
如果客戶端想關(guān)閉HTTP連接,可以在請求頭中攜帶Connection:false來告知服務(wù)器關(guān)閉請求。
HTTP1.1支持請求管道化(pipelining)。
基于HTTP1.1的長連接,使得請求管線化成為可能。 管線化使得請求能夠“并行”傳輸。
例如:
假如響應(yīng)的主體是一個html頁面,頁面中包含了很多img,這個時候keep-alive就了很大作用。能夠“并行”發(fā)送多個請求。(注意,這里的“并行”并不是真正意義上的并行傳輸)
需要注意的是:服務(wù)器必須按照客戶端請求的先后順序依次回送相應(yīng)的結(jié)果,以保證客戶端能夠區(qū)分出每次請求的響應(yīng)內(nèi)容。
也就是說,HTTP管道化可以讓我們把先進(jìn)先出隊列從客戶端(請求隊列)遷移到服務(wù)端(響應(yīng)隊列)
如果,客戶端同時發(fā)了兩個請求分別獲取html和css,假如說服務(wù)器的css資源先準(zhǔn)備就緒,服務(wù)器也會先發(fā)送html,再發(fā)送css。 換句話來說,只有等到html響應(yīng)的資源完全傳輸完畢后,css響應(yīng)的資源才開始傳輸,不允許同時存在兩個并行的響應(yīng)。
可見,HTTP1.1還是無法解決隊頭阻塞(head of line blocking)的問題。同時“管道化”技術(shù)存在各種各樣的問題,所以很多瀏覽器要么根本不支持它,要么直接默認(rèn)關(guān)閉,并且開啟的條件很苛刻……而且好像實際也沒有什么用處。
HTTP1.1支持管道化,但是服務(wù)器也必須進(jìn)行逐個響應(yīng)的送回,這個是很大的一個缺陷。實際上,現(xiàn)階段的瀏覽器廠商采取了另外一種做法,它允許我們打開多個TCP的會話,也就是說,上圖我們看到的并行,其實是不同的TCP連接上的HTTP請求和相應(yīng)。這才是真正的并行!
很多人以為的連接數(shù)情況:
實際情況(china):
此外,HTTP1.1還加入了緩存處理(強緩存和協(xié)商緩存),新的字段如cache-control,支持?jǐn)帱c傳輸,以及增加了Host字段(使得一個服務(wù)器能夠用來創(chuàng)建多個Web站點)
HTTP2.0通過在應(yīng)用層和傳輸層之間增加一個二進(jìn)制分層幀,突破了HTTP1.1的性能限制,改進(jìn)傳輸性能。
所有HTTP2.0通信都在一個TCP鏈接上完成,這個鏈接可以承載任意流量的雙向數(shù)據(jù)流。
每個數(shù)據(jù)流以消息的形式發(fā)送,而消息由一或多個幀組成。這些幀可以亂序發(fā)送,然后再根據(jù)每個幀頭部的流標(biāo)識符(Stream_id)重新封裝。
多路復(fù)用(連接共享)可能會導(dǎo)致關(guān)鍵字被阻塞,HTTP2.0里每個數(shù)據(jù)流都可以設(shè)置優(yōu)先級和依賴,優(yōu)先級高的數(shù)據(jù)流會被服務(wù)器優(yōu)先處理和返回客戶端,數(shù)據(jù)流還可以依賴其他的子數(shù)據(jù)流。
可見,HTTP2.0實現(xiàn)了真正的并行傳輸,它能夠在一個TCP上進(jìn)行任意數(shù)量的HTTP請求。而這個強大的功能基于“二級制分幀”的特性。
在HTTP1.X中,頭部元數(shù)據(jù)都是以純文本的形式發(fā)送的,通常會給每個請求增加500-8000字節(jié)的負(fù)荷。
比如cookie,默認(rèn)情況下,瀏覽器會在每次請求的時候,把cookie附在header上面發(fā)給服務(wù)器。
HTTP2.0使用encoder來減少需要傳輸?shù)膆eader大小,通訊雙方各自cache一份header_files表,既避免重復(fù)header的傳輸,又減少了需要傳輸?shù)拇笮 ?/span>
高效的壓縮算法可以很大的壓縮header,減少發(fā)送包的數(shù)量從而降低延遲。
服務(wù)器除了最初請求的響應(yīng)外,服務(wù)器還可以額外向客戶端推送資源,而無需客戶端明確的需求。
Google搞了一個基于UDP協(xié)議的QUIC協(xié)議,并且使用在了HTTP/3上, HTTP/3之前的名稱為HTTP-over-QUIC。
早期Quic協(xié)議,存在IETF和Google兩個版本,直到它被證實命名為HTTP3.0
IETF的QUIC工作小組創(chuàng)造了QUIC傳輸協(xié)議。QUIC是一個使用UDP來替代TCP的協(xié)議。最初的時候,Google開始助力QUIC,其后QUIC更多地被叫做“HTTP/2-encrypted-over-UDP “。
社區(qū)中的人們已經(jīng)使用非正式名稱如iQUIC和gQUIC來指代這些不同版本的協(xié)議,以將QUIC協(xié)議與IETF和Google分開(因為它們在細(xì)節(jié)上差異很大)。通過“iQUIC”發(fā)送HTTP的協(xié)議被稱為“HQ”(HTTP-over-QUIC)很長一段時間。
2018年11月7日,Litespeed的Dmitri宣布他們和Facebook已經(jīng)成功地完成了兩個HTTP/3實現(xiàn)之間的第一次互操作。Mike Bihop在該主題的HTTPBIS會話中的后續(xù)介紹可以在這里看到。會議結(jié)束時達(dá)成共識稱新名稱是HTTP/3!
緩存當(dāng)前會話的上下文,下次恢復(fù)會話的時候,只需要將之前的緩存?zhèn)鬟f給服務(wù)器,驗證通過,就可以進(jìn)行傳輸了。
0-RTT建連可以說是QUIC相比HTTP2最大的性能優(yōu)勢。
什么是0-RTT建連?
QUIC基于UDP,一個連接上的多個stream之間沒有依賴,即使丟包,只需要重發(fā)丟失的包即可,不需要重傳整個連接。
QUIC在移動端的表現(xiàn)比TCP好,因為TCP是基于IP識別連接,而QUIC是通過ID識別鏈接。 無論網(wǎng)絡(luò)環(huán)境如何變化,只要ID不便,就能迅速重新連上。
TCP協(xié)議頭沒有經(jīng)過任何加密和認(rèn)證,在傳輸過程中很容易被中間網(wǎng)絡(luò)設(shè)備篡改、注入和竊聽。
QUIC的packet可以說武裝到了牙齒,除了個別報文,比如PUBLIC_RESET和CHLO,所有報文頭部都是經(jīng)過認(rèn)證的,報文Body都是經(jīng)過加密的。
所以只要對 QUIC 做任何更改,接收端都能及時發(fā)現(xiàn),有效地降低了安全風(fēng)險。
QUIC協(xié)議有一個非常獨特的特性,稱為向前糾錯(Foward Error Connec,F(xiàn)EC),每個數(shù)據(jù)包除了它本身的內(nèi)容之外還包括了其他數(shù)據(jù)包的數(shù)據(jù),因此少量的丟包可以通過其他包的冗余數(shù)據(jù)直接組裝而無需重傳。
向前糾錯犧牲了每個數(shù)據(jù)包可以發(fā)送數(shù)據(jù)的上限,但是帶來的提升大于丟包導(dǎo)致的數(shù)據(jù)重傳,因為數(shù)據(jù)重傳將會消耗更多的時間(包括確認(rèn)數(shù)據(jù)包丟失,請求重傳,等待新數(shù)據(jù)包等步驟的時間消耗)。
例如:
沒有必要。
在頭部壓縮技術(shù)中,客戶端和服務(wù)器均會維護(hù)兩份相同的靜態(tài)字典和動態(tài)字典。
在靜態(tài)字典中,包含了常見的頭部名稱與值的組合。靜態(tài)字典在首次請求時可以使用。那么現(xiàn)在頭部的字段就可以被簡寫成靜態(tài)字典中相應(yīng)字段的index。
而動態(tài)字典跟連接的上下文相關(guān),每個HTTP/2連接維護(hù)的動態(tài)字典不盡相同。動態(tài)字典可以在連接不停地進(jìn)行更新。
也就是說,原本完整的HTTP報文頭部的鍵值或字段,由于字典的存在,現(xiàn)在可以轉(zhuǎn)換成索引index,在相應(yīng)的端再進(jìn)行查找還原,也就起到了壓縮的作用。
所以,同一個鏈接上產(chǎn)生的請求和響應(yīng)越多,動態(tài)字典累積得越全,頭部壓縮的效果也就越好,所以針對HTTP/2網(wǎng)站,最佳實踐是不要合并資源。
另外,HTTP2.0多路復(fù)用,使得請求可以并行傳輸,而HTTP1.1合并請求的一個原因也是為了防止過多的HTTP請求帶來的阻塞問題。而現(xiàn)在HTTP2.0已經(jīng)能夠并行傳輸了,所以合并請求也就沒有必要了。
由于HTTP/2使用了多路復(fù)用,一般來說,同一個域名下只需要使用一個TCP鏈接,但當(dāng)這個連接中出現(xiàn)了丟包的情況,就會導(dǎo)致HTTP/2的表現(xiàn)情況反倒不如HTTP/2了。
原因是: 在出現(xiàn)丟包的額情況下,整個TCP都要開始等待重傳,導(dǎo)致后面的所有數(shù)據(jù)都被阻塞。
但是對于HTTP/1.1來說,可以開啟多個TCP連接,出現(xiàn)這種情況只會影響其中一個連接,剩余的TCP鏈接還可以正常傳輸數(shù)據(jù)。
由于修改TCP協(xié)議是不可能完成的任務(wù)。
MTF在資源服務(wù)器和內(nèi)容分發(fā)節(jié)點都已經(jīng)啟用了 HTTP3.0 協(xié)議,根據(jù) 用戶瀏覽器 向下兼容,強烈建議您在Chrome瀏覽器開啟實驗性QUICK協(xié)議支持,體驗加速效果:
基于UDP實現(xiàn)
0RTT建連
基于UDP的多路復(fù)用
加密認(rèn)證的報文
向前糾錯機制
文章持續(xù)更新,可以公眾號搜一搜「 一角錢技術(shù) 」第一時間閱讀, 本文 GitHub org_hejianhui/JavaStudy 已經(jīng)收錄,歡迎 Star。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。