整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

HTML页面基本结构和加载过程

家好,我是皮皮。

前言

对于前端来说,HTML 都是最基础的内容。

今天,我们来了解一下 HTML 和网页有什么关系,以及与 DOM 有什么不同。通过本讲内容,你将掌握浏览器是怎么处理 HTML 内容的,以及在这个过程中我们可以进行怎样的处理来提升网页的性能,从而提升用户的体验。


一、浏览器页面加载过程

不知你是否有过这样的体验:当打开某个浏览器的时候,发现一直在转圈,或者等了好长时间才打开页面……

此时的你,会选择关掉页面还是耐心等待呢?

这一现象,除了网络不稳定、网速过慢等原因,大多数都是由于页面设计不合理导致加载时间过长导致的。

我们都知道,页面是用 HTML/CSS/JavaScript 来编写的。

  • HTML 的职责在于告知浏览器如何组织页面,以及搭建页面的基本结构;
  • CSS 用来装饰 HTML,让我们的页面更好看;
  • JavaScript 则可以丰富页面功能,使静态页面动起来。

HTML由一系列的元素组成,通常称为HTML元素。HTML 元素通常被用来定义一个网页结构,基本上所有网页都是这样的 HTML 结构:

<html>
    <head></head>
    <body></body>
</html>

其中:

  • html元素是页面的根元素,它描述完整的网页;
  • head元素包含了我们想包含在 HTML 页面中,但不希望显示在网页里的内容;
  • body元素包含了我们访问页面时所有显示在页面上的内容,是用户最终能看到的内容;


HTML 中的元素特别多,其中还包括可用于 Web Components 的自定义元素。

前面我们提到页面 HTML 结构不合理可能会导致页面响应慢,这个过程很多时候体现在<script><style>元素的设计上,它们会影响页面加载过程中对 Javascript 和 CSS 代码的处理。

因此,如果想要提升页面的加载速度,就需要了解浏览器页面的加载过程是怎样的,从根本上来解决问题。

浏览器在加载页面的时候会用到 GUI 渲染线程和 JavaScript 引擎线程(更详细的浏览器加载和渲染机制将在第 7 讲中介绍)。其中,GUI 渲染线程负责渲染浏览器界面 HTML 元素,JavaScript 引擎线程主要负责处理 JavaScript 脚本程序。

由于 JavaScript 在执行过程中还可能会改动界面结构和样式,因此它们之间被设计为互斥的关系。也就是说,当 JavaScript 引擎执行时,GUI 线程会被挂起。

以网易云课堂官网为例,我们来看看网页加载流程。

(1)当我们打开官网的时候,浏览器会从服务器中获取到 HTML 内容。

(2)浏览器获取到 HTML 内容后,就开始从上到下解析 HTML 的元素。

(3)<head>元素内容会先被解析,此时浏览器还没开始渲染页面。

我们看到<head>元素里有用于描述页面元数据的<meta>元素,还有一些<link>元素涉及外部资源(如图片、CSS 样式等),此时浏览器会去获取这些外部资源。除此之外,我们还能看到<head>元素中还包含着不少的<script>元素,这些<script>元素通过src属性指向外部资源。

(4)当浏览器解析到这里时(步骤 3),会暂停解析并下载 JavaScript 脚本。

(5)当 JavaScript 脚本下载完成后,浏览器的控制权转交给 JavaScript 引擎。当脚本执行完成后,控制权会交回给渲染引擎,渲染引擎继续往下解析 HTML 页面。

(6)此时<body>元素内容开始被解析,浏览器开始渲染页面。

在这个过程中,我们看到<head>中放置的<script>元素会阻塞页面的渲染过程:把 JavaScript 放在<head>里,意味着必须把所有 JavaScript 代码都下载、解析和解释完成后,才能开始渲染页面。

到这里,我们就明白了:如果外部脚本加载时间很长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,用户体验会变得很糟糕。

因此,对于对性能要求较高、需要快速将内容呈现给用户的网页,常常会将 JavaScript 脚本放在<body>的最后面。这样可以避免资源阻塞,页面得以迅速展示。我们还可以使用defer/async/preload等属性来标记<script>标签,来控制 JavaScript 的加载顺序。

百度首页

三、DOM 解析

对于百度这样的搜索引擎来说,必须要在最短的时间内提供到可用的服务给用户,其中就包括搜索框的显示及可交互,除此之外的内容优先级会相对较低。

浏览器在渲染页面的过程需要解析 HTML、CSS 以得到 DOM 树和 CSS 规则树,它们结合后才生成最终的渲染树并渲染。因此,我们还常常将 CSS 放在<head>里,可用来避免浏览器渲染的重复计算。


二、HTML 与 DOM 有什么不同

我们知道<p>是 HTML 元素,但又常常将<p>这样一个元素称为 DOM 节点,那么 HTML 和 DOM 到底有什么不一样呢?

根据 MDN 官方描述:文档对象模型(DOM)是 HTML 和 XML 文档的编程接口。

也就是说,DOM 是用来操作和描述 HTML 文档的接口。如果说浏览器用 HTML 来描述网页的结构并渲染,那么使用 DOM 则可以获取网页的结构并进行操作。一般来说,我们使用 JavaScript 来操作 DOM 接口,从而实现页面的动态变化,以及用户的交互操作。

在开发过程中,常常用对象的方式来描述某一类事物,用特定的结构集合来描述某些事物的集合。DOM 也一样,它将 HTML 文档解析成一个由 DOM 节点以及包含属性和方法的相关对象组成的结构集合。


三、DOM 解析

我们常见的 HTML 元素,在浏览器中会被解析成节点。比如下面这样的 HTML 内容:

<html>
    <head>
        <title>标题</title>
    </head>
    <body>
        <a href='xx.com'>我的超链接</a>
        <h1>页面第一标题</h1>
    </body>
</html>

打开控制台 Elements 面板,可以看到这样的 HTML 结构,如下图所示:

在浏览器中,上面的 HTML 会被解析成这样的 DOM 树,如下图所示:


我们都知道,对于树状结构来说,常常使用parent/child/sibling等方式来描述各个节点之间的关系,对于 DOM 树也不例外。

举个例子,我们常常会对页面功能进行抽象,并封装成组件。但不管怎么进行整理,页面最终依然是基于 DOM 的树状结构,因此组件也是呈树状结构,组件间的关系也同样可以使用parent/child/sibling这样的方式来描述。同时,现在大多数应用程序同样以root为根节点展开,我们进行状态管理、数据管理也常常会呈现出树状结构。


四、事件委托

我们知道,浏览器中各个元素从页面中接收事件的顺序包括事件捕获阶段、目标阶段、事件冒泡阶段。其中,基于事件冒泡机制,我们可以实现将子元素的事件委托给父级元素来进行处理,这便是事件委托。

如果我们在每个元素上都进行监听的话,则需要绑定三个事件;(假设页面上有a,b,c三个兄弟节点)

function clickEventFunction(e) {
  console.log(e.target === this); // logs `true`
  // 这里可以用 this 获取当前元素
}
// 元素a,b,c绑定
element2.addEventListener("click", clickEventFunction, false);
element5.addEventListener("click", clickEventFunction, false);
element8.addEventListener("click", clickEventFunction, false);

使用事件委托,可以通过将事件添加到它们的父节点,而将事件委托给父节点来触发处理函数:

function clickEventFunction(event) {
  console.log(e.target === this); // logs `false`
  // 获取被点击的元素
  const eventTarget = event.target;
  // 检查源元素`event.target`是否符合预期
  // 此处控制广告面板的展示内容
}
// 元素1绑定
element1.addEventListener("click", clickEventFunction, false);

这样能解决什么问题呢?

  • 绑定子元素会绑定很多次的事件,而绑定父元素只需要一次绑定。
  • 将事件委托给父节点,这样我们对子元素的增加和删除、移动等,都不需要重新进行事件绑定。

常见的使用方式主要是上述这种列表结构,每个选项都可以进行编辑、删除、添加标签等功能,而把事件委托给父元素,不管我们新增、删除、更新选项,都不需要手动去绑定和移除事件。

如果在列表数量内容较大的时候,对成千上万节点进行事件监听,也是不小的性能消耗。使用事件委托的方式,我们可以大量减少浏览器对元素的监听,也是在前端性能优化中比较简单和基础的一个做法。

注意:

  1. 如果我们直接在document.body上进行事件委托,可能会带来额外的问题;
  2. 由于浏览器在进行页面渲染的时候会有合成的步骤,合成的过程会先将页面分成不同的合成层,而用户与浏览器进行交互的时候需要接收事件。此时,浏览器会将页面上具有事件处理程序的区域进行标记,被标记的区域会与主线程进行通信。
  3. 如果我们document.body上被绑定了事件,这时候整个页面都会被标记;
  4. 即使我们的页面不关心某些部分的用户交互,合成器线程也必须与主线程进行通信,并在每次事件发生时进行等待。这种情况,我们可以使用passive: true选项来解决


五、总结

我们了解了 HTML 的作用,以及它是如何影响浏览器中页面的加载过程的,同时还介绍了使用 DOM 接口来控制 HTML 的展示和功能逻辑。我们了解了DOM解析事件委托等相关概念。

<!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">学术</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>网盘</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>经验</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="#">设置</a>
				<div id="F">
					<a href="#">搜索设置</a><br>
					<a href="#">高级搜索</a><br>
					<a href="#">关闭预测</a><br>
					<a href="#">隐私设置</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.官方调查女教师</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.蔡丽不再担任武汉市医院书记</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省区市新增境外输入9例</a></td>
				</tr>
			</table>
		</div>
		<div id="db">
			<ul>
				<li>设为首页</li>
				<li>关于百度</li>
				<li>About Baidu</li>
				<li>百度营销</li>
				<li>使用百度前必读</li>
				<li>意见反馈</li>
				<li>帮助中心</li>
			</ul>
		</div>
		<div id="div1">
			<ul>
				
			
			<li>@2020 Baidu</li>
			<li>(京)-经营性-2017-0020</li>
			<li>京公网安备11000002000001号</li>
			<li>京ICP证030173号</li></ul>
		</div>
	</body>
</html>

上代码写出来的结果如下图:


新手勿喷!!!

者公众号:org_yijiaoqian

HTTP1.0

1.0的HTTP版本,是一种无状态,无连接的应用层协议。 HTTP1.0规定浏览器和服务器保持短暂的链接。

浏览器每次请求都需要与服务器建立一个TCP连接,服务器处理完成以后立即断开TCP连接(无连接),服务器不跟踪也每个客户单,也不记录过去的请求(无状态)。

这种无状态性可以借助cookie/session机制来做身份认证和状态记录。

HTTP1.0存在的问题

无法复用连接

每次发送请求,都需要进行一次TCP连接,而TCP的连接释放过程又是比较费事的。这种无连接的特性会使得网络的利用率变低。

队头阻塞(head of line blocking)

由于HTTP1.0规定下一个请求必须在前一个请求响应到达之前才能发送,假设前一个请求响应一直不到达,那么下一个请求就不发送,后面的请求就阻塞了。

HTTP1.1

HTTP1.1继承了HTTP1.0的简单,克服了HTTP1.0性能上的问题。

长连接

HTTP1.1增加Connection字段,通过设置Keep-Alive保持HTTP连接不断卡。避免每次客户端与服务器请求都要重复建立释放建立TCP连接。提高了网络的利用率。

如果客户端想关闭HTTP连接,可以在请求头中携带Connection:false来告知服务器关闭请求。

管道化(pipelining)— 尴尬的假并行传输

HTTP1.1支持请求管道化(pipelining)。

基于HTTP1.1的长连接,使得请求管线化成为可能。 管线化使得请求能够“并行”传输。

例如

假如响应的主体是一个html页面,页面中包含了很多img,这个时候keep-alive就了很大作用。能够“并行”发送多个请求。(注意,这里的“并行”并不是真正意义上的并行传输

需要注意的是:服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。

也就是说,HTTP管道化可以让我们把先进先出队列从客户端(请求队列)迁移到服务端(响应队列)

如果,客户端同时发了两个请求分别获取html和css,假如说服务器的css资源先准备就绪,服务器也会先发送html,再发送css。 换句话来说,只有等到html响应的资源完全传输完毕后,css响应的资源才开始传输,不允许同时存在两个并行的响应。

可见,HTTP1.1还是无法解决队头阻塞(head of line blocking)的问题。同时“管道化”技术存在各种各样的问题,所以很多浏览器要么根本不支持它,要么直接默认关闭,并且开启的条件很苛刻……而且好像实际也没有什么用处。

真并行传输 — 浏览器优化策略

HTTP1.1支持管道化,但是服务器也必须进行逐个响应的送回,这个是很大的一个缺陷。实际上,现阶段的浏览器厂商采取了另外一种做法,它允许我们打开多个TCP的会话,也就是说,上图我们看到的并行,其实是不同的TCP连接上的HTTP请求和相应。这才是真正的并行!

很多人以为的连接数情况:


实际情况(china):


缓存处理 — 强缓存、协商缓存,启发式缓存(新增)

此外,HTTP1.1还加入了缓存处理(强缓存和协商缓存),新的字段如cache-control,支持断点传输,以及增加了Host字段(使得一个服务器能够用来创建多个Web站点)

HTTP2.0

二进制分帧

HTTP2.0通过在应用层和传输层之间增加一个二进制分层帧,突破了HTTP1.1的性能限制,改进传输性能。

多路复用(链接共享)— 真并行传输

  • 流(stream):已建立连接上的双向字节流。
  • 消息:与逻辑消息对应的完整的一系列数据帧。
  • 帧(frame):HTTP2.0通信的最小单位,每个帧包含头部,至少也会标识出当前所属的流(stream_id)

所有HTTP2.0通信都在一个TCP链接上完成,这个链接可以承载任意流量的双向数据流。

每个数据流以消息的形式发送,而消息由一或多个帧组成。这些帧可以乱序发送,然后再根据每个帧头部的流标识符(Stream_id)重新封装。

多路复用(连接共享)可能会导致关键字被阻塞,HTTP2.0里每个数据流都可以设置优先级和依赖,优先级高的数据流会被服务器优先处理和返回客户端,数据流还可以依赖其他的子数据流。

可见,HTTP2.0实现了真正的并行传输,它能够在一个TCP上进行任意数量的HTTP请求。而这个强大的功能基于“二级制分帧”的特性。

头部压缩

在HTTP1.X中,头部元数据都是以纯文本的形式发送的,通常会给每个请求增加500-8000字节的负荷。

比如cookie,默认情况下,浏览器会在每次请求的时候,把cookie附在header上面发给服务器。

HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header_files表,既避免重复header的传输,又减少了需要传输的大小。

高效的压缩算法可以很大的压缩header,减少发送包的数量从而降低延迟。

服务器推送

服务器除了最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确的需求。

HTTP3.0

Google搞了一个基于UDP协议的QUIC协议,并且使用在了HTTP/3上, HTTP/3之前的名称为HTTP-over-QUIC。

早期Quic协议,存在IETF和Google两个版本,直到它被证实命名为HTTP3.0

IETF的QUIC工作小组创造了QUIC传输协议。QUIC是一个使用UDP来替代TCP的协议。最初的时候,Google开始助力QUIC,其后QUIC更多地被叫做“HTTP/2-encrypted-over-UDP “。

社区中的人们已经使用非正式名称如iQUIC和gQUIC来指代这些不同版本的协议,以将QUIC协议与IETF和Google分开(因为它们在细节上差异很大)。通过“iQUIC”发送HTTP的协议被称为“HQ”(HTTP-over-QUIC)很长一段时间。

2018年11月7日,Litespeed的Dmitri宣布他们和Facebook已经成功地完成了两个HTTP/3实现之间的第一次互操作。Mike Bihop在该主题的HTTPBIS会话中的后续介绍可以在这里看到。会议结束时达成共识称新名称是HTTP/3!

0-RTT — QUIC协议相比HTTP2.0的最大优势

缓存当前会话的上下文,下次恢复会话的时候,只需要将之前的缓存传递给服务器,验证通过,就可以进行传输了。

0-RTT建连可以说是QUIC相比HTTP2最大的性能优势。

什么是0-RTT建连

  • 传输层0-RTT就能建立连接
  • 加密层0-RTT就能建立加密连接

多路复用

QUIC基于UDP,一个连接上的多个stream之间没有依赖,即使丢包,只需要重发丢失的包即可,不需要重传整个连接。

更好的移动端表现

QUIC在移动端的表现比TCP好,因为TCP是基于IP识别连接,而QUIC是通过ID识别链接。 无论网络环境如何变化,只要ID不便,就能迅速重新连上。

加密认证的根文 — 武装到牙齿

TCP协议头没有经过任何加密和认证,在传输过程中很容易被中间网络设备篡改、注入和窃听。

QUIC的packet可以说武装到了牙齿,除了个别报文,比如PUBLIC_RESET和CHLO,所有报文头部都是经过认证的,报文Body都是经过加密的。

所以只要对 QUIC 做任何更改,接收端都能及时发现,有效地降低了安全风险。

向前纠错机制

QUIC协议有一个非常独特的特性,称为向前纠错(Foward Error Connec,FEC),每个数据包除了它本身的内容之外还包括了其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。

向前纠错牺牲了每个数据包可以发送数据的上限,但是带来的提升大于丢包导致的数据重传,因为数据重传将会消耗更多的时间(包括确认数据包丢失,请求重传,等待新数据包等步骤的时间消耗)。

例如:

  • 我总共发送三个包,协议会算出这个三个包的异或值并单独发出一个校验包,也就是总共发出了四个包。
  • 当其中出现了非校验包丢失的情况,可以通过另外三个包计算出丢失的数据包的内容。
  • 当然这种技术只能使用在丢失一个包的情况下,如果出现丢失多个包,就不能使用纠错机制了,只能使用重传的方式了。

问题归纳

HTTP1.1的合并请求(如CSSsprites)是否适用于HTTP2.0

没有必要。

在头部压缩技术中,客户端和服务器均会维护两份相同的静态字典动态字典

在静态字典中,包含了常见的头部名称与值的组合。静态字典在首次请求时可以使用。那么现在头部的字段就可以被简写成静态字典中相应字段的index。

而动态字典跟连接的上下文相关,每个HTTP/2连接维护的动态字典不尽相同。动态字典可以在连接不停地进行更新。

也就是说,原本完整的HTTP报文头部的键值或字段,由于字典的存在,现在可以转换成索引index,在相应的端再进行查找还原,也就起到了压缩的作用。

所以,同一个链接上产生的请求和响应越多,动态字典累积得越全,头部压缩的效果也就越好,所以针对HTTP/2网站,最佳实践是不要合并资源

另外,HTTP2.0多路复用,使得请求可以并行传输,而HTTP1.1合并请求的一个原因也是为了防止过多的HTTP请求带来的阻塞问题。而现在HTTP2.0已经能够并行传输了,所以合并请求也就没有必要了。

为什么要有HTTP3.0:HTTP/2底层TCP的局限带来的问题

由于HTTP/2使用了多路复用,一般来说,同一个域名下只需要使用一个TCP链接,但当这个连接中出现了丢包的情况,就会导致HTTP/2的表现情况反倒不如HTTP/2了。

原因是: 在出现丢包的额情况下,整个TCP都要开始等待重传,导致后面的所有数据都被阻塞。

但是对于HTTP/1.1来说,可以开启多个TCP连接,出现这种情况只会影响其中一个连接,剩余的TCP链接还可以正常传输数据。

由于修改TCP协议是不可能完成的任务。

如何在Chrome中启用 QUIC 协议

MTF在资源服务器和内容分发节点都已经启用了 HTTP3.0 协议,根据 用户浏览器 向下兼容,强烈建议您在Chrome浏览器开启实验性QUICK协议支持,体验加速效果:

  1. 在浏览器地址栏:输入chrome://flags
  2. 找到Experimental QUIC protocol,将Default改为Enabled


总结

HTTP 1.0

  • 无状态,无连接
  • 短连接:每次发送请求都要重新建立tcp请求,即三次握手,非常浪费性能
  • 无host头域,也就是http请求头里的host,
  • 不允许断点续传,而且不能只传输对象的一部分,要求传输整个对象


HTTP 1.1

  • 长连接,流水线,使用connection:keep-alive使用长连接
  • 请求管道化
  • 增加缓存处理(新的字段如cache-control)
  • 增加Host字段,支持断点传输等
  • 由于长连接会给服务器造成压力


HTTP 2.0

  • 二进制分帧
  • 头部压缩,双方各自维护一个header的索引表,使得不需要直接发送值,通过发送key缩减头部大小
  • 多路复用(或连接共享),使用多个stream,每个stream又分帧传输,使得一个tcp连接能够处理多个http请求
  • 服务器推送(Sever push)


HTTP 3.0

  • 基于google的QUIC协议,而quic协议是使用udp实现的
  • 减少了tcp三次握手时间,以及tls握手时间
  • 解决了http 2.0中前一个stream丢包导致后一个stream被阻塞的问题
  • 优化了重传策略,重传包和原包的编号不同,降低后续重传计算的消耗
  • 连接迁移,不再用tcp四元组确定一个连接,而是用一个64位随机数来确定这个连接
  • 更合适的流量控制

基于UDP实现

0RTT建连

基于UDP的多路复用

加密认证的报文

向前纠错机制

文章持续更新,可以公众号搜一搜「 一角钱技术 」第一时间阅读, 本文 GitHub org_hejianhui/JavaStudy 已经收录,欢迎 Star。