0%

三万长文50+趣图带你领悟web编程的内功心法

看到题目,大家是不是认为根据上一篇一样,其实不然,我们上一边介绍的是网络编程的基本功,有了这些基本功之后,我们就可以在此之上构建更加接近实际应用的web程序了。为了快速展示他们的层次关系,我用几本书叠了起来进行说明,顺便给大家推荐这几本基本算是这些领域比较权威的书籍。如下图,由下往上看:

image-20200913190523972

  • TCP/IP构成了网络编程的基础设施;
  • Socket套接字编程为应用层提供了访问TCP/IP协议栈的接口;
  • 在应用层上面,指定了面向Web编程的HTTP协议;
  • Tomcat是实现HTTP协议的一个应用服务器。

两万字长文50+张趣图带你领悟网络编程的内功心法 一文中,我们详细介绍了TCP/IP协议,从物理层一直讲到了应用层。在应用层可以利用TCP/IP底层的能力,实现丰富的功能,而本文,我们就重点讲解构建在应用层上的协议:HTTP协议。

首先,我们来思考一个问题,HTTP是怎么来的,为什么要创造HTTP,HTTP接下来会怎么发展呢?这就得聊聊HTTP的发展演变史了。

阅读本文的同时,我们可以看到整个HTTP的发展演变史,可以发现,假设规范是一个小伙子,一般来说,一个优秀的小伙子从来不是出生之后就是优秀的,而是随着业务场景,技术挑战的产生,不断的被拉去劳改,学习,在忧患中蜕变进化。所以现在所谓的标准、成熟的技术,未必符合所有的场景,是技术的挑战与创新促成了新事务的发展。

(前方高能预警:此处有篇高考高分作文💯...)如果Google只满足于HTTP/1.1,就不会推出SPDY促进HTTP/2的诞生了;如果Google只满足于SPDY,就不会推出QUIC促进HTTP/3的诞生了;如果快手只满足于HTTP/1.1,就不会自己实现一套kQUIC了;如果我只满足于通过HttpClient发起HTTP调用,就不会写这篇文章了。

还记得那个学术风浓厚的OSI网络模型吗,最终是被TCP/IP给盖过了风头。**深入应用场景,深入业务,挖掘痛点,探索折腾起来吧。**哦对了,最重要的一点:计算机基础知识得打牢固。

1、HTTP发展演变史

话不多少,我直接画了一个图,总结一下HTTP的演变史,一个从诞生之日开始就不断被劳改的小伙子,一路被互联网巨头和互联网标准化组织IETF逐渐带上正轨的心酸历史,它还有很长一段路需要走:

image-20200913211955666

image-20200816161701982

1.1、时代背景

在HTTP协议诞生以前,都有哪些事情的发生,为其做好了铺垫呢?下面来看看。

image-20200816161641063

接下来,我会请出我们的机器人为我们总结每个小节的技术,格式如下:

image-20200816182046028

每个版本的协议都会有很多特性,这个章节会把相关特性或者技术点描述出来,但是在发展演变史这章节不会细讲,我们后面会有专门章节为你揭秘HTTP技术点的详细实现原理。

所以,本章节主要是为您梳理HTTP的发展演变史,知道技术的来龙去脉,以及接下来的发展趋势。

1.1.1、ARPANET

ARPANET(Advanced Research Projects Agency Network)是第一个具有分布式控制的广域分组交换网络,该网络由美国国防部高级研究计划局建立。

为了实现对远程计算机的访问,美国互联网先驱 Bob Taylor 在1966年启动了ARPANET项目,1969年连接了第一台计算机,在1970年实现了网络控制程序。

关于为何要搞这样的技术,据ARPA的总监Charles Herzfeld说:因为当时美国直邮数量有限的大型的研究计算机,而许多应该使用这些计算机的研究人员由于地理空间问题导致不能很好使用起来,这使他们感到很挫败,所以就提出了这个研究计划。当然也有传言是处于军事目的,实现对核力量的控制,改善军事战术和管理决策。但不管怎样,网络世界从此往前迈进了一大步。

image-20200816184337629

1.1.2、TCP/IP

在70年代的时候,基于ARPA网络的发展,研究人员指定了传输控制方案,最终演变成了一个协议,通过该协议可以将多个单独的网络合成一个网络,这个协议也就是TCP/IP。

在1983年UNIX操作系统BSD诞生了,其内核就包含了网络编程套接字的设计和实现,TCP/IP就这么被BSD带起来了,最终逐渐成为了事实的标准。

可以说UNIX套接字联网API就是网络编程的一个源头了,所以大学老师教网络编程的时候大概率会推荐这本书:《UNIX网络编程 卷1:套接字联网API》,当时我们老师也推荐了这本书,虽然当时大概率不会细看,但是迟早会用到的。

image-20200816184508075

1.1.3、OSI参考模型

两万字长文50+张趣图带你领悟网络编程的内功心法 一文我们也提到了,为了制定一个统一的计算机网络体系,国际标准化组织ISO提出了一个试图使各种计算机可以在世界范围内互联成网的标准框架:OSI/RM(Open System Interconnection Reference Model 开放系统互连基本参考模型)。

不过嘛,这个标准是1984年发布的,此时TCP/IP已占据大半江山,逐渐成为了事实的标准,而且OSI更加学术,上一篇文章我们也提到了OSI的一些缺点,导致其不能取代TCP/IP,TCP/IP则是在实践中得到了验证。

1.1.4、World Wide Web

好了,万事具备,我们离HTTP的诞生越来越接近了。

在1989年,英国工程师兼计算机科学家 Timothy Berners-Lee 在1989年发明了World Wide Web万维网,万维网是信息时代发展的核心。他开发了三种基础技术:

  • URI:统一资源标识符;
  • HTML:超文本标记语言;
  • HTTP:超文本传输协议;

是什么促成了 Timothy Berners-Lee 发明万维网呢?在CERN工作的时候,他对查找存储在不同计算机上的信息所带来的低效率和困难感到沮丧。于是,他想CERN管理层提交了一份备忘录:《信息管理:一项提案》。逐渐促成了可以在文档中通过单击鼠标跳转到其他引用的文档的系统的实现,这种呈现形式的文档被称为超文本

HTTP诞生了。

image-20200816184431658

1.2、HTTP/0.9

1991年,是一个单纯的年代,网上只有文字,看不了图,看不了片。在如此单纯的环境下,Timothy Berners-Lee设计了HTTP协议的0.9版本,为啥不给多个0.1凑个整呢,因为跟我们现在用的HTTP1.1+协议比起来实在是简单多了:

  • 基于客户端服务端的请求响应协议;
  • 没有首部;
  • 没有状态码;
  • 只支持纯文本,其设计目标是获取HTML;
  • 只支持GET方法;
  • 每次请求都建立新的TCP连接;

但是这也是满足那个纯真年代的需求了。保持简单,避免过度设计也好,为后续扩展留了个口子。

image-20200816184603785

1.2.1、报文示例

HTTP/0.9协议下通过浏览器访问:https://www.itzhai.com/hello-world.html

在建立了TCP连接之后,最终浏览器会发送报文如下:

1
GET /hello-world.html

GET后面为什么是资源路径,而不是URL呢?

因为浏览器首先是拿到了URL对应的IP地址,然后建立TCP连接,一旦连接到服务器,就不需要协议,服务器,和端口号了。第二节我们会抓包演示。

响应也非常简单,仅仅由HTML文件本身组成:

1
2
3
4
5
<html>
<body>
welcome to itzhai (www.itzhai.com), wechat account: itread.
</body>
</html>

可以发现:

  • 没有HTTP首部,也就意味着只能传输HTML文件;
  • 没有状态码:出现问题的时候,只能发送一个特定的HTML文件,其中包含问题的描述,以供人们解读错误信息。

1.3、HTTP/1.0

人们的欲望是那么的没有止境呀,后来又想在网上看小图片,又想听音乐,不单单只是看文字了,还想自己写段子到网上。这么多需求来了,只能升级HTTP协议了。在1996年5月,HTTP工作组发布了RFC 1945[1],在该文档中记录了许多HTTP/1.0实现的通用方法,于是HTTP/1.0就诞生了。

HTTP/1.0跟我现在用的HTTP/1.1比接近了,加了如下概念:

  • 增加了首部:

    • Allow
    • Authorization
    • Content-Encoding
    • Content-Length
    • Content-Type
    • Date
    • Expires
    • From
  • 增加了16个响应状态码;

  • 引入了重定向;

  • 内容编码(压缩):

    • 1
      content-coding = "x-gzip" | "x-compress" | token
  • 更多的请求方法:GET,HEAD,POST;

  • 传输数据不限于文本;

更详细的内容,参考RFC 1945[1:1]

但是,HTTP/1.0并不是一个正是规范或Interger标准,只是一个已有实践的参考文档,没有约束力,对当时的互联网来说没有太大的推进作用。

另外,HTTP/1.0也是有很多瑕疵的,比如不能让多个请求共用一个TCP连接,缺少强制的Host首部,并且缓存比较控制比较粗糙。

image-20200816184132917

如何复用TCP连接?

有些浏览器在请求的时候,会使用一个非标准的Connection字段:

1
2
> Connection: keep-alive
>

这个表示客户端端要求服务器不要关闭TCP连接,以便其他请求可以复用,服务器同样的回应这个字段。

1.3.1、报文示例

HTTP/1.0协议下通过浏览器访问:https://www.itzhai.com/hello-world2.html

请求报文如下所示:

1
2
3
GET /hello-world2.html HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
Accept: */*

响应报文如下所示:

1
2
3
4
5
6
7
8
9
10
11
200 OK
Date: Tue, 15 Nov 1996 08:00:00 GMT
Server: Apache 0.84
Content-Type: text/html

<html>
<body>
welcome to itzhai (www.itzhai.com), wechat account: itread.<br/>
<img src="https://www.itzhai.com/resources/images/itzhai_qrcode.jpeg" width="100px">
</body>
</html>

由于浏览器拿到响应的HTML之后,解析到里面还有一个img图片请求,于是又发起了第二个连接获取图片:

1
2
GET /resources/images/itzhai_qrcode.jpeg HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)

响应报文如下所示:

1
2
3
4
5
6
200 OK
Date: Tue, 15 Nov 1996 08:00:01 GMT
Server: Apache 0.84
Content-Type: image/jpeg

(image content)

1.4、HTTP/1.1

将HTTP转变为正式的IETF Internet标准的工作与围绕HTTP/1.0文档编制工作并行进行。

有道是,有竞争才会有进步,微软在1995年推出的Windows系统中发布了IE浏览器,与当时的浏览器霸主Netscape浏览器展开对抗,IE逐步占有了更多的市场,直到1998年Netscape被AOL收购后,IE的市场还在不断攀升,在两大浏览器互相厮杀期间,HTTP/1.1诞生了。

image-20200816191000557

在1997年1月,发布了HTTP/1.1的第一个正式标准 RFC2068[2]。然后,在两年半之后的1999年6月,许多改进和更新被纳入该标准,并以 RFC 2616[3]的形式发布。

HTTP/1.1有如下特性:

  • 新增了POTIONS、PUT、DELETE、TRACE、CONNECT等新方法;

  • 强化了缓存管理和控制;

  • 支持维持持久连接,支持通知服务器弃用连接;也就是说TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive

  • 请求HTML文件的时候要求携带编码、字符集、cookie元数据等信息;

  • 支持原始HTML请求的分块响应,利于传输大文件;

就这样,一个最稳定版本的HTTP协议诞生了,直到现在,仍然有很多网站在使用HTTP/1.1协议。

image-20200816183918954

在HTTP/1.1期间,涌现了很多互联网企业,如,Google,腾讯,百度,阿里,淘宝,美团头条等。

image-20200816191319930

1.4.1、报文示例

请求报文:

1
2
3
4
5
6
7
8
9
10
11
GET /hello-world2.html HTTP/1.1
Host: www.itzhai.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
If-None-Match: "9a3bee90-q1"
If-Modified-Since: Tue, 18 Aug 2020 15:06:33 GMT

响应报文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HTTP/1.1 200 OK
Date: Tue, 18 Aug 2020 15:30:57 GMT
Last-Modified: Tue, 18 Aug 2020 15:06:33 GMT
Content-Type: text/html
Content-Length: 192
ETag: "5f3bee79-c0"
Accept-Ranges: bytes

<html>
<body>
welcome to itzhai (www.itzhai.com), wechat account: itread.<br/>
<img src="https://www.itzhai.com/resources/images/itzhai_qrcode.jpeg" width="200px">
</body>
</html>

HTTP/1.1具体特性说明我们第二节会讲到。

1.5、HTTP/2

当然,HTTP/1.1的问题也是很多的,主要是连接缓慢,服务器只能按顺序响应,如果某个请求花了很长时间,就会出现请求队头阻塞,从而影响其他请求。

这个时期出现了很多各式的前端优化小技巧,当年搞过一段时间前端,也对这些技术略知一二,如:

  • 为了增加并发请求,做域名拆分;
  • CSS、JS等资源内联到HTML中,或者进行资源合并;
  • 生成精灵图,一次性传输所有小图标;
  • 资源预取...

最终,为了推进从协议上进行优化,Google跳出来了,推出了SPDY协议。

1.5.1、SPDY

为啥Google敢推出这样的协议呢,主要还是因为在2008年诞生的Chrome浏览器迅速占据了市场,拥有了大部分用户,挟天子以令诸侯,尝试推广新技术是水到渠成的事情。

image-20200816191558976

SPDY是Google开发,用于传输Web内容的协议,SPDY协议减少了网页加载延迟,并且提高了We标的安全性。

SPDY主要通过帧和首部压缩、多路复用和优先级属性降低等待时间。

SPDY诞生之后,很快被整合进Chrome和Firefox,最终被所有主流浏览器所采用,另外服务器和网络代理也对SPDY提供了必要的支持。

SPDY的核心人员后来都参与到了HTTP/2的开发,在2015年2月,Google宣布最终批准HTTP/2标准之后,也就不再继续支持SPDY协议了,并且最终在Google Chrome 51中删除了SPDY的支持。

1.5.2、HTTP/2

HTTP/2又解决了HTTP/1.1面临的大部分问题,主要有如下功能:

  • 使用虚拟的流传输消息,解决了HTTP一个连接中应用层的队头阻塞的问题;
  • 使用了二进制协议,不再是纯文本,避免文本歧义,缩小了请求体积;
  • 实现了多路复用,提高了连接的利用率,在拥塞控制方面有了更好的能力提升;
  • 使用HPACK首部压缩方案压缩头部信息,大大节约了带宽;
  • 增强了安全性,使用HTTP/2,要求必须至少用TLS1.2;
  • 允许服务器主动向客户端推送数据;

image-20200816184010614

1.6、HTTP/3

HTTP/2还在草案的时候,Google又发现新的问题了,那就是由于HTTP/2依赖于TCP,TCP有什么问题,那么HTTP/2就会存在什么问题。最主要的问题还是队头阻塞问题:队头阻塞问题在应用层解决了,但是在TCP协议层并没有解决:

  • 上一篇文章我们提到过TCP在丢包的时候会进行重传,前面有一个包没有接收到,就只能把后面的包先放到缓冲区里面,应用层实际上是无法取数据的。也就是说HTTP / 2的多路复用的并行性对于TCP的丢失恢复机制不管用,因此丢失或者重新排序的数据报都会导致所有活动事务陷入停顿。

为了解决以上问题,于是Google发明了gQUIC(Quick UDP Internet Connection)协议。

1.6.1、QUIC

QUIC是最初由Google开发的一种传输层网络协议,在QUIC协议中,传输层用UDP替换掉了TCP,并在用户空间实现了一套拥塞控制算法,从而避免了TCP的队头阻塞问题。

在UDP之上,QUIC实现了连接管理、拥塞窗口、流量控制等。

后来IETF HTTP和QUIC工作组主席Mark Nottingham提出了正式请求,将HTTP-over-QUIC重命名为HTTP/3。

###1.6.2、HTTP/3

HTTP / 3使用与HTTP/1.1和HTTP/2相同的语义(相同的操作,例如GET和POST)和相同的响应代码(例如200或404),但是使用QUIC传输协议协议,以及采用类似于HTTP/2的内部成帧层提供HTTP语义的传输。

image-20200816184054126

HTTP/3进展如何?

截止到2020年8月,HTTP/3协议已经成为Internet草案,并且具有多种实现方案,前1000万个网站中有6.7%支持HTTP / 3。在浏览器方面,Firefox和Chrome稳定版本都支持HTTP/3,但是默认情况下是禁用的,Safari 14将默认启用HTTP/3。

想进一步了解,可以阅读最新的发布于2020年8月14日的HTTP/3草案:Hypertext Transfer Protocol Version 3 (HTTP/3)[4]


目前我们使用最广发的还是HTTP/1.1,接下来我就基于HTTP/1.1来介绍下HTTP协议。

接下来,由于篇幅所限,为了给大家呈现更好的阅读体验,我把后续的内容分为以下章节,深入细节更精彩,欢迎大家继续阅读:

章节 内容说明
第一章:HTTP发展演变史 从历史的角度介绍了HTTP协议发展的来来龙去脉,每个版本迭代的事件背景,以及每个版本的优缺点,让您对HTTP协议有一个系统的了解。
第二章:初识HTTP/1.1 简单介绍了HTTP协议的基本特点,后续章节会基于这些特点详细展开说明。
第三章:HTTP/1.1报文详解 根据HTTP RFC规范文档内容,详细描述了HTTP报文的格式,本章节比较枯燥,可以大概涉略下,后续可以作为查阅参考内容。
第四章:HTTP常用请求头大揭秘 介绍了HTTP中最常见的请求头,包含:编码、内容协商、分块传输、范围请求、连接管理、Cookie机制,缓存机制、代理、重定向等,基本上是web开发很常见的特性。
第五章:HTTPS:网络安全攻坚战 详细介绍了HTTPS,包括发展历史,关键的TLS层加密详解,以及HTTPS连接过程说明。
第六章:HTTP/2:网络安全传输的快车道 从HTTP/1.1的缺点展开,介绍了:二进制帧、头信息压缩、流传输、安全升级、ALPN、服务器推送等HTTP/2强大的特性。
第七章:HTTP/3:让传输效率再一次起飞 由于HTTP/3还未正式发布,这里只做了基本特性的说明。

References

  • 谢希仁. 计算机网络(第6版). 电子工业出版社.
  • TCP/IP详解 卷1:协议(原书第2版). 机械工业出版社.
  • UNIX网络编程 卷1:套接字联网API. 人民邮电出版社
  • HTTP权威指南. 人民邮电出版社
  • HTTP/2基础教程. 人民邮电出版社
  • 刘超. 趣谈网络协议. 极客时间
  • 罗剑锋. 透视HTTP协议. 即可时间

  1. Hypertext Transfer Protocol -- HTTP/1.0 RFC 1945. Retrieved from https://datatracker.ietf.org/doc/rfc1945/ ↩︎ ↩︎

  2. HypertextTransferProtocol--HTTP/1.1 2068. Retrieved from https://tools.ietf.org/html/rfc2068 ↩︎

  3. Hypertext Transfer Protocol -- HTTP/1.1 2616. Retrieved from https://tools.ietf.org/html/rfc2616 ↩︎

  4. Hypertext Transfer Protocol Version 3 (HTTP/3). Retrieved from https://quicwg.org/base-drafts/draft-ietf-quic-http.html ↩︎

欢迎关注我的其它发布渠道