HTTP的发展历史

HTTP是互联网的基础协议,也是数据传输的重要组成,本文主要介绍HTTP1.1 和 HTTP2.0, 以及HTTP的历史演进以及设计思路。在学习HTTP之前,我们先来了解HTTP的概念。

HTTP: 超文本传输协议(HyperText Transfer Protocol), 是一种用于分布式、协作式和超媒体信息系统的应用层协议, 是万维网的数据通信的基础,基于TCP/IP通信协议来传递数据,它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口。

image

HTTP0.9

最早版本是1991年发布的0.9版。该版本极其简单,只有一个命令GET,不支持请求头。

image

HTTP/0.9具有典型的无状态性,每个事务独立进行处理,事务结束时就释放这个连接。

HTTP1.0

1996年5月,HTTP/1.0 版本发布,是HTTP协议的第二个版本,此协议版本是第一个在通讯中指定版本号的HTTP协议版本,至今仍被沿用,此版亦增加了很多新特性,如引入请求头和响应头。

一、响应对象不只限于超文本,还可以接受图、音视频、二进制文件等文件,为互联网的大发展奠定了基础

二、新增请求方法,如head/post,丰富了浏览器与服务器的交互手段

三、增加缓存功能,已请求过的内容再次请求时就可直接使用缓存

四、增加请求头、响应头,让请求和相应都更清晰

image
  • accept 解决文件格式问题,是json还是html,浏览器根据不同文件格式来解析文件

  • accept-charset 解决文件编码问题,告知浏览器如何将字符流解析成字节流

  • accept-encoding 解决大文件压缩问题,浏览器采用指定的解压方式来解压

  • accept-language 解决国际化问题,不同国家请求不同语言的文件

    其他的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、内容编码(content encoding)等

缺点:

1、每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。默认使用短链接(除非手动设置),会增加大量无谓的开销,比如TCP建立连接需要三次握手等(后面再详解TCP连接建立)

2、只有前一个请求完,才可以发送下一个请求,如果某个请求没有及时返回,容易造成队头阻塞

3、不支持断点续传等等

为了解决这些问题,推出了HTTP1.1

HTTP1.1

1997年1月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了20年后的今天,,是目前使用最广泛的协议版本。HTTP/1.1是目前主流的HTTP协议版本,相对于HTTP/1.0新增了以下内容

**1. 默认为长连接 **

HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection:keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。

<pre style="margin: 0px; padding: 0px; color: rgb(51, 51, 51); font-size: 17px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接.</pre>

2. 管道机制

把先进先出(FIFO)队列从客户端(请求队列)移到服务端(响应队列),这样在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。

3、提供了范围请求功能(宽带优化)****

HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。这是支持文件断点续传的基础。

4.提供了虚拟主机的功能(HOST域)

在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。

5.多了一些缓存处理字段

HTTP/1.1在1.0的基础上加入了一些cache的新特性,引入了实体标签,一般被称为e-tags,新增更为强大的Cache-Control头。

6.Content-Length 字段

一个TCP连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是Content-length字段的作用,声明本次回应的数据长度,如

<pre style="margin: 0px; padding: 0px; color: rgb(51, 51, 51); font-size: 17px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Content-Length: 3495</pre>

这行代码告诉浏览器,本次回应的长度是3495个字节,后面的字节就属于下一个回应了。

7.分块传输编码

响应体可以分块传输,无需一次传输全部内容,使用Content-Length字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。

因此,1.1版规定可以不使用Content-Length字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有Transfer-Encoding字段,就表明回应将由数量未定的数据块组成。

image

1.1版还新增了许多数据交互方法:PUT、PATCH、HEAD、 OPTIONS、DELETE

缺点:

虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。

为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS代码、域名分片(domain sharding)等等。如果HTTP协议设计得更好一些,这些额外的工作是可以避免的。

HTTP2.0

2015年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3, HTTP2.0主要包括以下内容

1. 二进制分帧

HTTP 2.0 的所有帧都采用二进制编码

帧:客户端与服务器通过交换帧来通信,帧是基于这个新协议通信的最小单位。

消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。

流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2 … N);

HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多

2.多路复用

有了新的分帧机制后,HTTP/2.0不再依赖多个TCP 连接去处理更多并发的请求。每个数据流都拆分成很多互不依赖的帧,而这些帧可以交错(乱序发送),还可以分优先级。最后再在另一端根据每个帧首部的流标识符把它们重新组合起来。HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个连接)即可。在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞".

3.头部压缩

HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。

HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

4.数据流

因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。

HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数

数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。

客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接

5.服务端推送

服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。

缺点:

HTTP2.0 TCP然是顺序发送,顺序接收的,依然有队头堵塞问题,TCP握手过程导致连接超时,也是影响数据传输效率的重要因素。于是,google带头对TCP和UDP进行改造整合,推出HTTP3.0

image

HTTP3.0

HTTP3.0又称为HTTP Over QUIC,其弃用TCP协议,改为使用基于UDP协议的QUIC协议来实现。

1、修复队头阻塞 Head-of-line blocking

队头阻塞 是计算机网络中是一种性能受限的现象,通俗来说就是:一个数据包影响了一堆数据包,它不来大家都走不了。

2、0RTT 建链

衡量网络建链的常用指标是RTT Round-Trip Time,也就是数据包一来一回的时间消耗。RTT包括三部分:往返传播时延、网络设备内排队时延、应用程序数据处理时延。

简单来说,基于TCP协议和TLS协议的HTTP2.0在真正发送数据包之前需要花费一些时间来完成握手和加密协商,完成之后才可以真正传输业务数据。

但是QUIC则第一个数据包就可以发业务数据,从而在连接延时有很大优势,可以节约数百毫秒的时间。

了解完HTTP的发展历史以及每个版本协议的特点后,下一篇文章,将对https进行一些简单梳理,在梳理之前,我们一起来解答一下,上一篇文章留下的思考题。(仅供参考)

如何编写V8友好的高性能javascript代码?

1、隐藏类(hidden class)的教训

  • 在构造函数里初始化所有对象的成员(所以这些实例之后不会改变其隐藏类)

  • 总是以相同的次序初始化对象成员

  • 永远不要delete对象的某个属性

image

在以上例子中p2.z破坏了上述原则, 将导致p1与p2使用了不同的隐藏类。在我们为p2添加“z”这个成员之前,p1和p2一直共享相同的内部隐藏类——所以V8可以生成一段单独版本的优化汇编码,这段代码可以同时封装p1和p2的JavaScript代码。派生出这个新的隐藏类还将使编译器无法在optimized模式执行。我们越避免隐藏类的派生,就会获得越高的性能。

image

以上例子由于调用了delete,将导致hidden class产生变化,导致p1.y不能用inline cache直接获取。以上程序在使用了delete之后耗时0.339s,在注释掉delete后只需0.05s

2、deoptimized的教训

  • 单态操作优于多态操作

  • 谨慎使用try catch与for in

image

如果一个操作的输入总是相同类型的,则其为单态操作。否则,操作调用时的某个参数可以跨越不同的类型,那就是多态操作。比如add()的第二个调用就触发了多态操作:

3、内存管理与GC的教训

闭包会使程序逻辑变复杂,有时会看不清楚是否对象内存被释放,因此要注意释放闭包中的大对象, 否则会引起内存泄露。

一些异步操作如timer(timeout/setInterval)等也会造成内存泄漏

4、使用数字的教训

当类型可以改变时,V8使用标记来高效的标识其值。V8通过其值来推断你会以什么类型的数字来对待它。因为这些类型可以动态改变,所以一旦V8完成了推断,就会通过标记高效完成值的标识。不过有的时候改变类型标记还是比较消耗性能的,我们最好保持数字的类型始终不变。通常标识为有符号的31位整数是最优的。

优化手段都在我们日常代码的编写当中,以上也只是总结了一部分优化手段,也欢迎小伙伴积极投稿,一起共建前端代码规范。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容