This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
<audio id="audio" title="01 | 时势与英雄HTTP的前世今生" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/94/33/945bf44de1d08d72f9ce94d290401733.mp3"></audio>
HTTP协议在我们的生活中随处可见打开手机或者电脑只要你上网不论是用iPhone、Android、Windows还是Mac不论是用浏览器还是App不论是看新闻、短视频还是听音乐、玩游戏后面总会有HTTP在默默为你服务。
据NetCraft公司统计目前全球至少有16亿个网站、2亿多个独立域名而这个庞大网络世界的底层运转机制就是HTTP。
那么在享受如此便捷舒适的网络生活时你有没有想过HTTP协议是怎么来的它最开始是什么样子的又是如何一步一步发展到今天几乎“统治”了整个互联网世界的呢
常言道:“**时势造英雄,英雄亦造时势**”。
今天我就和你来聊一聊HTTP的发展历程看看它的成长轨迹看看历史上有哪些事件推动了它的前进它又促进了哪些技术的产生一起来见证“英雄之旅”。
在这个过程中你也能够顺便了解一下HTTP的“历史局限性”明白HTTP为什么会设计成现在这个样子。
## 史前时期
20世纪60年代美国国防部高等研究计划署ARPA建立了ARPA网它有四个分布在各地的节点被认为是如今互联网的“始祖”。
然后在70年代基于对ARPA网的实践和思考研究人员发明出了著名的TCP/IP协议。由于具有良好的分层结构和稳定的性能TCP/IP协议迅速战胜其他竞争对手流行起来并在80年代中期进入了UNIX系统内核促使更多的计算机接入了互联网。
## 创世纪
<img src="https://static001.geekbang.org/resource/image/a2/9a/a2960d0e44ef6a8fedd4e9bb836e049a.jpg" alt="unpreview">
1989年任职于欧洲核子研究中心CERN的蒂姆·伯纳斯-李Tim Berners-Lee发表了一篇论文提出了在互联网上构建超链接文档系统的构想。这篇论文中他确立了三项关键技术。
1. URI即统一资源标识符作为互联网上资源的唯一身份
1. HTML即超文本标记语言描述超文本文档
1. HTTP即超文本传输协议用来传输超文本。
这三项技术在如今的我们看来已经是稀松平常但在当时却是了不得的大发明。基于它们就可以把超文本系统完美地运行在互联网上让各地的人们能够自由地共享信息蒂姆把这个系统称为“万维网”World Wide Web也就是我们现在所熟知的Web。
所以在这一年我们的英雄“HTTP”诞生了从此开始了它伟大的征途。
## HTTP/0.9
20世纪90年代初期的互联网世界非常简陋计算机处理能力低存储容量小网速很慢还是一片“信息荒漠”。网络上绝大多数的资源都是纯文本很多通信协议也都使用纯文本所以HTTP的设计也不可避免地受到了时代的限制。
这一时期的HTTP被定义为0.9版,结构比较简单,为了便于服务器和客户端处理,它也采用了纯文本格式。蒂姆·伯纳斯-李最初设想的系统里的文档都是只读的所以只允许用“GET”动作从服务器上获取HTML文档并且在响应请求之后立即关闭连接功能非常有限。
HTTP/0.9虽然很简单但它作为一个“原型”充分验证了Web服务的可行性而“简单”也正是它的优点蕴含了进化和扩展的可能性因为
“把简单的系统变复杂”,要比“把复杂的系统变简单”容易得多。
## HTTP/1.0
1993年NCSA美国国家超级计算应用中心开发出了Mosaic是第一个可以图文混排的浏览器随后又在1995年开发出了服务器软件Apache简化了HTTP服务器的搭建工作。
同一时期计算机多媒体技术也有了新的发展1992年发明了JPEG图像格式1995年发明了MP3音乐格式。
这些新软件新技术一经推出立刻就吸引了广大网民的热情更的多的人开始使用互联网研究HTTP并提出改进意见甚至实验性地往协议里添加各种特性从用户需求的角度促进了HTTP的发展。
于是在这些已有实践的基础上经过一系列的草案HTTP/1.0版本在1996年正式发布。它在多方面增强了0.9版形式上已经和我们现在的HTTP差别不大了例如
1. 增加了HEAD、POST等新方法
1. 增加了响应状态码,标记可能的错误原因;
1. 引入了协议版本号概念;
1. 引入了HTTP Header头部的概念让HTTP处理请求和响应更加灵活
1. 传输的数据不再仅限于文本。
但HTTP/1.0并不是一个“标准”,只是记录已有实践和模式的一份参考文档,不具有实际的约束力,相当于一个“备忘录”。
所以HTTP/1.0的发布对于当时正在蓬勃发展的互联网来说并没有太大的实际意义,各方势力仍然按照自己的意图继续在市场上奋力拼杀。
## HTTP/1.1
1995年网景的Netscape Navigator和微软的Internet Explorer开始了著名的“浏览器大战”都希望在互联网上占据主导地位。
<img src="https://static001.geekbang.org/resource/image/94/42/9470d41cab80f36438ebb06a71672242.png" alt="unpreview">
这场战争的结果你一定早就知道了最终微软的IE取得了决定性的胜利而网景则“败走麦城”但后来却凭借Mozilla Firefox又扳回一局
“浏览器大战”的是非成败我们放在一边暂且不管不可否认的是它再一次极大地推动了Web的发展HTTP/1.0也在这个过程中经受了实践检验。于是在“浏览器大战”结束之后的1999年HTTP/1.1发布了RFC文档编号为2616正式确立了延续十余年的传奇。
从版本号我们就可以看到HTTP/1.1是对HTTP/1.0的小幅度修正。但一个重要的区别是它是一个“正式的标准”而不是一份可有可无的“参考文档”。这意味着今后互联网上所有的浏览器、服务器、网关、代理等等只要用到HTTP协议就必须严格遵守这个标准相当于是互联网世界的一个“立法”。
不过说HTTP/1.1是“小幅度修正”也不太确切它还是有很多实质性进步的。毕竟经过了多年的实战检验比起0.9/1.0少了“学术气”更加“接地气”同时表述也更加严谨。HTTP/1.1主要的变更点有:
1. 增加了PUT、DELETE等新的方法
1. 增加了缓存管理和控制;
1. 明确了连接管理,允许持久连接;
1. 允许响应数据分块chunked利于传输大文件
1. 强制要求Host头让互联网主机托管成为可能。
HTTP/1.1的推出可谓是“众望所归”互联网在它的“保驾护航”下迈开了大步由此走上了“康庄大道”开启了后续的“Web 1.0”“Web 2.0”时代。现在许多的知名网站都是在这个时间点左右创立的例如Google、新浪、搜狐、网易、腾讯等。
不过由于HTTP/1.1太过庞大和复杂所以在2014年又做了一次修订原来的一个大文档被拆分成了六份较小的文档编号为7230-7235优化了一些细节但此外没有任何实质性的改动。
## HTTP/2
HTTP/1.1发布之后整个互联网世界呈现出了爆发式的增长度过了十多年的“快乐时光”更涌现出了Facebook、Twitter、淘宝、京东等互联网新贵。
这期间也出现了一些对HTTP不满的意见主要就是连接慢无法跟上迅猛发展的互联网但HTTP/1.1标准一直“岿然不动”无奈之下人们只好发明各式各样的“小花招”来缓解这些问题比如以前常见的切图、JS合并等网页优化手段。
终于有一天搜索巨头Google忍不住了决定“揭竿而起”就像马云说的“如果银行不改变我们就改变银行”。那么它是怎么“造反”的呢
Google首先开发了自己的浏览器Chrome然后推出了新的SPDY协议并在Chrome里应用于自家的服务器如同十多年前的网景与微软一样从实际的用户方来“倒逼”HTTP协议的变革这也开启了第二次的“浏览器大战”。
历史再次重演不过这次的胜利者是GoogleChrome目前的全球的占有率超过了60%。“挟用户以号令天下”Google借此顺势把SPDY推上了标准的宝座互联网标准化组织以SPDY为基础开始制定新版本的HTTP协议最终在2015年发布了HTTP/2RFC编号7540。
HTTP/2的制定充分考虑了现今互联网的现状宽带、移动、不安全在高度兼容HTTP/1.1的同时在性能改善方面做了很大努力,主要的特点有:
1. 二进制协议,不再是纯文本;
1. 可发起多个请求废弃了1.1里的管道;
1. 使用专用算法压缩头部,减少数据传输量;
1. 允许服务器主动向客户端推送数据;
1. 增强了安全性,“事实上”要求加密通信。
虽然HTTP/2到今天已经四岁也衍生出了gRPC等新协议但由于HTTP/1.1实在是太过经典和强势目前它的普及率还比较低大多数网站使用的仍然还是20年前的HTTP/1.1。
## HTTP/3
看到这里你可能会问了“HTTP/2这么好是不是就已经完美了呢
答案是否定的这一次还是Google而且它要“革自己的命”。
在HTTP/2还处于草案之时Google又发明了一个新的协议叫做QUIC而且还是相同的“套路”继续在Chrome和自家服务器里试验着“玩”依托它的庞大用户量和数据量持续地推动QUIC协议成为互联网上的“既成事实”。
“功夫不负有心人”当然也是因为QUIC确实自身素质过硬。
在去年也就是2018年互联网标准化组织IETF提议将“HTTP over QUIC”更名为“HTTP/3”并获得批准HTTP/3正式进入了标准化制订阶段也许两三年后就会正式发布到时候我们很可能会跳过HTTP/2直接进入HTTP/3。
## 小结
今天我和你一起跨越了三十年的历史长河回顾了HTTP协议的整个发展过程在这里简单小结一下今天的内容
1. HTTP协议始于三十年前蒂姆·伯纳斯-李的一篇论文;
1. HTTP/0.9是个简单的文本协议,只能获取文本资源;
1. HTTP/1.0确立了大部分现在使用的技术,但它不是正式标准;
1. HTTP/1.1是目前互联网上使用最广泛的协议,功能也非常完善;
1. HTTP/2基于Google的SPDY协议注重性能改善但还未普及
1. HTTP/3基于Google的QUIC协议是将来的发展方向。
希望通过今天的介绍你能够对HTTP有一个初步但清晰的印象知道了“来龙”才能更好地知道“去脉”。
## 课下作业
1. 你认为推动HTTP发展的原动力是什么
1. 你是怎么理解HTTP超文本传输协议
欢迎你把自己的答案写在留言区,与我和其他同学一起讨论。暂时回答不出来也不要紧,你可以带着这些问题在后续的课程里寻找答案。
如果你觉得有所收获,欢迎你把文章分享给你的朋友。
<img src="https://static001.geekbang.org/resource/image/20/00/2016d4e0ab9698c3d2cd560f0fa89a00.png" alt="unpreview">

View File

@@ -0,0 +1,141 @@
<audio id="audio" title="02 | HTTP是什么HTTP又不是什么" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/bd/46/bd2f893babbff670fb54341068f21a46.mp3"></audio>
首先我来问出这个问题“你觉得HTTP是什么呢
你可能会不假思索、脱口而出“HTTP就是超文本传输协议也就是**H**yper**T**ext **T**ransfer **P**rotocol。”
回答非常正确我必须由衷地恭喜你能给出这个答案就表明你具有至少50%HTTP相关的知识储备应该算得上是“半个专家”了。
不过让我们换个对话场景,假设不是我,而是由一位面试官问出刚才的问题呢?
<img src="https://static001.geekbang.org/resource/image/b4/bf/b4de4be0f7dfd4185464bb5a1d6df0bf.png" alt="unpreview">
显然,这个答案有点过于简单了,不能让他满意,他肯定会再追问你一些问题:
- 你是怎么理解HTTP字面上的“超文本”和“传输协议”的
- 能否谈一下你对HTTP的认识越多越好。
- HTTP有什么特点有什么优点和缺点
- HTTP下层都有哪些协议是如何工作的
- ……
几乎所有面试时问到的HTTP相关问题都可以从这个最简单的“HTTP是什么”引出来。
所以,今天的话题就从这里开始,深度地解答一下“**HTTP是什么**”,以及延伸出来的第二个问题“**HTTP不是什么**”
## HTTP是什么
咱们中国有个成语“人如其名”,意思是一个人的性格和特点是与他的名字相符的。
先看一下HTTP的名字“**超文本传输协议**”,它可以拆成三个部分,分别是:“**超文本**”“**传输**”和“**协议**”。我们从后往前来逐个解析理解了这三个词我们也就明白了什么是HTTP。
<img src="https://static001.geekbang.org/resource/image/d6/20/d697ba915bcca40a11b8a25571516720.jpg" alt="unpreview">
首先HTTP是一个**协议**。不过,协议又是什么呢?
其实“协议”并不仅限于计算机世界,现实生活中也随处可见。例如,你在刚毕业时会签一个“三方协议”,找房子时会签一个“租房协议”,公司入职时还可能会签一个“保密协议”,工作中使用的各种软件也都带着各自的“许可协议”。
刚才说的这几个都是“协议”本质上与HTTP是相同的那么“协议”有什么特点呢
第一点,协议必须要有两个或多个参与者,也就是“协”。
如果**只有**你一个人,那你自然可以想干什么就干什么,想怎么玩就怎么玩,不会干涉其他人,其他人也不会干涉你,也就不需要所谓的“协议”。但是,一旦有了两个以上的参与者出现,为了保证最基本的顺畅交流,协议就自然而然地出现了。
例如,为了保证你顺利就业,“三方协议”里的参与者有三个:你、公司和学校;为了保证你顺利入住,“租房协议”里的参与者有两个:你和房东。
第二点,协议是对参与者的一种行为约定和规范,也就是“议”。
协议意味着有多个参与者为了达成某个共同的目的而站在了一起,除了要无疑义地沟通交流之外,还必须明确地规定各方的“责、权、利”,约定该做什么不该做什么,先做什么后做什么,做错了怎么办,有没有补救措施等等。例如,“租房协议”里就约定了,租期多少个月,每月租金多少,押金是多少,水电费谁来付,违约应如何处理等等。
到这里你应该能够明白HTTP的第一层含义了。
HTTP是一个用在计算机世界里的协议。它使用计算机能够理解的语言确立了一种计算机之间交流通信的规范以及相关的各种控制和错误处理方式。
接下来我们看HTTP字面里的第二部分“**传输**”。
计算机和网络世界里有数不清的各种角色CPU、内存、总线、磁盘、操作系统、浏览器、网关、服务器……这些角色之间相互通信也必然会有各式各样、五花八门的协议用处也各不相同例如广播协议、寻址协议、路由协议、隧道协议、选举协议等等。
HTTP是一个“**传输协议**”所谓的“传输”Transfer其实很好理解就是把一堆东西从A点搬到B点或者从B点搬到A点即“A&lt;===&gt;B”。
别小看了这个简单的动作,它也至少包含了两项重要的信息。
第一点HTTP协议是一个“**双向协议**”。
也就是说有两个最基本的参与者A和B从A开始到B结束数据在A和B之间双向而不是单向流动。通常我们把先发起传输动作的A叫做**请求方**把后接到传输的B叫做**应答方**或者**响应方**。拿我们最常见的上网冲浪来举例子浏览器就是请求方A网易、新浪这些网站就是应答方B。双方约定用HTTP协议来通信于是浏览器把一些数据发送给网站网站再把一些数据发回给浏览器最后展现在屏幕上你就可以看到各种有意思的新闻、视频了。
第二点数据虽然是在A和B之间传输但并没有限制只有A和B这两个角色允许中间有“中转”或者“接力”。
这样传输方式就从“A&lt;===&gt;B”变成了“A&lt;=&gt;X&lt;=&gt;Y&lt;=&gt;Z&lt;=&gt;B”A到B的传输过程中可以存在任意多个“中间人”而这些中间人也都遵从HTTP协议只要不打扰基本的数据传输就可以添加任意的额外功能例如安全认证、数据压缩、编码转换等等优化整个传输过程。
说到这里你差不多应该能够明白HTTP的第二层含义了。
HTTP是一个在计算机世界里专门用来在两点之间传输数据的约定和规范。
讲完了“协议”和“传输”现在我们终于到HTTP字面里的第三部分“**超文本**”。
既然HTTP是一个“传输协议”那么它传输的“超文本”到底是什么呢我还是用两点来进一步解释。
所谓“**文本**”Text就表示HTTP传输的不是TCP/UDP这些底层协议里被切分的杂乱无章的二进制包datagram而是完整的、有意义的数据可以被浏览器、服务器这样的上层应用程序处理。
在互联网早期“文本”只是简单的字符文字但发展到现在“文本”的涵义已经被大大地扩展了图片、音频、视频、甚至是压缩包在HTTP眼里都可以算做是“文本”。
所谓“**超文本**”,就是“超越了普通文本的文本”,它是文字、图片、音频和视频等的混合体,最关键的是含有“超链接”,能够从一个“超文本”跳跃到另一个“超文本”,形成复杂的非线性、网状的结构关系。
对于“超文本”我们最熟悉的就应该是HTML了它本身只是纯文字文件但内部用很多标签定义了对图片、音频、视频等的链接再经过浏览器的解释呈现在我们面前的就是一个含有多种视听信息的页面。
OK经过了对HTTP里这三个名词的详细解释下次当你再面对面试官时就可以给出比“超文本传输协议”这七个字更准确更有技术含量的答案“HTTP是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范”。
## HTTP不是什么
现在你对“**HTTP是什么**”应该有了比较清晰的认识,紧接着的问题就是“**HTTP不是什么**”等价的问题是“HTTP不能干什么”。想想看你能回答出来吗
因为HTTP是一个协议是一种计算机间通信的规范所以它**不存在“单独的实体”**。它不是浏览器、手机APP那样的应用程序也不是Windows、Linux那样的操作系统更不是Apache、Nginx、Tomcat那样的Web服务器。
但HTTP又与应用程序、操作系统、Web服务器密切相关在它们之间的通信过程中存在而且是一种“动态的存在”是发生在网络连接、传输超文本数据时的一个“动态过程”。
**HTTP不是互联网**
互联网Internet是遍布于全球的许多网络互相连接而形成的一个巨大的国际网络在它上面存放着各式各样的资源也对应着各式各样的协议例如超文本资源使用HTTP普通文件使用FTP电子邮件使用SMTP和POP3等。
但毫无疑问HTTP是构建互联网的一块重要拼图而且是占比最大的那一块。
**HTTP不是编程语言**
编程语言是人与计算机沟通交流所使用的语言而HTTP是计算机与计算机沟通交流的语言我们无法使用HTTP来编程但可以反过来用编程语言去实现HTTP告诉计算机如何用HTTP来与外界通信。
很多流行的编程语言都支持编写HTTP相关的服务或应用例如使用Java在Tomcat里编写Web服务使用PHP在后端实现页面模板渲染使用JavaScript在前端实现动态页面更新你是否也会其中的一两种呢
**HTTP不是HTML**这个可能要特别强调一下千万不要把HTTP与HTML混为一谈虽然这两者经常是同时出现。
HTML是超文本的载体是一种标记语言使用各种标签描述文字、图片、超链接等资源并且可以嵌入CSS、JavaScript等技术实现复杂的动态效果。单论次数在互联网上HTTP传输最多的可能就是HTML但要是论数据量HTML可能要往后排了图片、音频、视频这些类型的资源显然更大。
**HTTP不是一个孤立的协议**
俗话说“一个好汉三个帮”HTTP也是如此。
在互联网世界里HTTP通常跑在TCP/IP协议栈之上依靠IP协议实现寻址和路由、TCP协议实现可靠数据传输、DNS协议实现域名查找、SSL/TLS协议实现安全通信。此外还有一些协议依赖于HTTP例如WebSocket、HTTPDNS等。这些协议相互交织构成了一个协议网而HTTP则处于中心地位。
## 小结
1. HTTP是一个用在计算机世界里的协议它确立了一种计算机之间交流通信的规范以及相关的各种控制和错误处理方式。
1. HTTP专门用来在两点之间传输数据不能用于广播、寻址或路由。
1. HTTP传输的是文字、图片、音频、视频等超文本数据。
1. HTTP是构建互联网的重要基础技术它没有实体依赖许多其他的技术来实现但同时许多技术也都依赖于它。
把这些综合起来使用递归缩写方式模仿PHP我们可以把HTTP定义为“**与HTTP协议相关的所有应用层技术的总和**”。
这里我画了一个思维导图,也可以算是这个专栏系列文章的“知识地图”。
<img src="https://static001.geekbang.org/resource/image/27/cc/2781919e73f5d258ff1dc371af632acc.png" alt="">
你可以对照这张图,看一下哪些部分是自己熟悉的,哪些部分是陌生的,又有哪些部分是想要进一步了解的,下一讲我会详细讲解这张图。
## 课下作业
1. 有一种流行的说法“HTTP是用于从互联网服务器传输超文本到本地浏览器的协议”你认为这种说法对吗对在哪里又错在哪里
1. 你能再说出几个“HTTP不是什么”吗
欢迎你通过留言分享答案,与我和其他同学一起讨论。如果你觉得有所收获,欢迎你把文章分享给你的朋友。
<img src="https://static001.geekbang.org/resource/image/eb/3a/ebcadbddbc7e0c146dbe7617a844e83a.png" alt="unpreview">

View File

@@ -0,0 +1,146 @@
<audio id="audio" title="03 | HTTP世界全览与HTTP相关的各种概念" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a5/98/a5050b7253387e72a48472ad47886198.mp3"></audio>
在上一讲的末尾我画了一张图里面是与HTTP关联的各种技术和知识点也可以说是这个专栏的总索引不知道你有没有认真看过呢
那张图左边的部分是与HTTP有关系的各种协议比较偏向于理论而右边的部分是与HTTP有关系的各种应用技术偏向于实际应用。
我希望借助这张图帮你澄清与HTTP相关的各种概念和角色让你在实际工作中清楚它们在链路中的位置和作用知道发起一个HTTP请求会有哪些角色参与会如何影响请求的处理做到“手中有粮心中不慌”。
因为那张图比较大所以我会把左右两部分拆开来分别讲今天先讲右边的部分也就是与HTTP相关的各种应用着重介绍互联网、浏览器、Web服务器等常见且重要的概念。
<img src="https://static001.geekbang.org/resource/image/51/64/5102fc33d04b59b36971a5e487779864.png" alt="">
为了方便你查看,我又把这部分重新画了一下,比那张大图小了一些,更容易地阅读,你可以点击查看。
暖场词就到这里,让我们正式开始吧。
## 网络世界
你一定已经习惯了现在的网络生活,甚至可能会下意识地认为网络世界就应该是这个样子的:“一张平坦而且一望无际的巨大网络,每一台电脑就是网络上的一个节点,均匀地点缀在这张网上”。
这样的理解既对,又不对。从抽象的、虚拟的层面来看,网络世界确实是这样的,我们可以从一个节点毫无障碍地访问到另一个节点。
但现实世界的网络却远比这个抽象的模型要复杂得多。实际的互联网是由许许多多个规模略小的网络连接而成的,这些“小网络”可能是只有几百台电脑的局域网,可能是有几万、几十万台电脑的广域网,可能是用电缆、光纤构成的固定网络,也可能是用基站、热点构成的移动网络……
互联网世界更像是由数不清的大小岛屿组成的“千岛之国”。
互联网的正式名称是Internet里面存储着无穷无尽的信息资源我们通常所说的“上网”实际上访问的只是互联网的一个子集“万维网”World Wide Web它基于HTTP协议传输HTML等超文本资源能力也就被限制在HTTP协议之内。
互联网上还有许多万维网之外的资源例如常用的电子邮件、BT和Magnet点对点下载、FTP文件下载、SSH安全登录、各种即时通信服务等等它们需要用各自的专有协议来访问。
不过由于HTTP协议非常灵活、易于扩展而且“超文本”的表述能力很强所以很多其他原本不属于HTTP的资源也可以“包装”成HTTP来访问这就是我们为什么能够总看到各种“网页应用”——例如“微信网页版”“邮箱网页版”——的原因。
综合起来看现在的互联网90%以上的部分都被万维网也就是HTTP所覆盖所以把互联网约等于万维网或HTTP应该也不算大错。
## 浏览器
上网就要用到浏览器常见的浏览器有Google的Chrome、Mozilla的Firefox、Apple的Safari、Microsoft的IE和Edge还有小众的Opera以及国内的各种“换壳”的“极速”“安全”浏览器。
<img src="https://static001.geekbang.org/resource/image/61/8b/613fffb6defee1735431dc5f89085d8b.png" alt="unpreview">
那么你想过没有,所谓的“浏览器”到底是个什么东西呢?
浏览器的正式名字叫“**Web Browser**”顾名思义就是检索、查看互联网上网页资源的应用程序名字里的Web实际上指的就是“World Wide Web”也就是万维网。
浏览器本质上是一个HTTP协议中的**请求方**使用HTTP协议获取网络上的各种资源。当然为了让我们更好地检索查看网页它还集成了很多额外的功能。
例如HTML排版引擎用来展示页面JavaScript引擎用来实现动态化效果甚至还有开发者工具用来调试网页以及五花八门的各种插件和扩展。
在HTTP协议里浏览器的角色被称为“User Agent”即“用户代理”意思是作为访问者的“代理”来发起HTTP请求。不过在不引起混淆的情况下我们通常都简单地称之为“客户端”。
## Web服务器
刚才说的浏览器是HTTP里的请求方那么在协议另一端的**应答方**(响应方)又是什么呢?
这个你一定也很熟悉,答案就是**服务器****Web Server**。
Web服务器是一个很大也很重要的概念它是HTTP协议里响应请求的主体通常也把控着绝大多数的网络资源在网络世界里处于强势地位。
当我们谈到“Web服务器”时有两个层面的含义硬件和软件。
**硬件**含义就是物理形式或“云”形式的机器,在大多数情况下它可能不是一台服务器,而是利用反向代理、负载均衡等技术组成的庞大集群。但从外界看来,它仍然表现为一台机器,但这个形象是“虚拟的”。
**软件**含义的Web服务器可能我们更为关心它就是提供Web服务的应用程序通常会运行在硬件含义的服务器上。它利用强大的硬件能力响应海量的客户端HTTP请求处理磁盘上的网页、图片等静态文件或者把请求转发给后面的Tomcat、Node.js等业务应用返回动态的信息。
比起层出不穷的各种Web浏览器Web服务器就要少很多了一只手的手指头就可以数得过来。
Apache是老牌的服务器到今天已经快25年了功能相当完善相关的资料很多学习门槛低是许多创业者建站的入门产品。
Nginx是Web服务器里的后起之秀特点是高性能、高稳定且易于扩展。自2004年推出后就不断蚕食Apache的市场份额在高流量的网站里更是不二之选。
此外还有Windows上的IIS、Java的Jetty/Tomcat等因为性能不是很高所以在互联网上应用得较少。
## CDN
浏览器和服务器是HTTP协议的两个端点那么在这两者之间还有别的什么东西吗
当然有了。浏览器通常不会直接连到服务器中间会经过“重重关卡”其中的一个重要角色就叫做CDN。
**CDN**全称是“Content Delivery Network”翻译过来就是“内容分发网络”。它应用了HTTP协议里的缓存和代理技术代替源站响应客户端的请求。
CDN有什么好处呢
简单来说它可以缓存源站的数据让浏览器的请求不用“千里迢迢”地到达源站服务器直接在“半路”就可以获取响应。如果CDN的调度算法很优秀更可以找到离用户最近的节点大幅度缩短响应时间。
打个比方,就好像唐僧西天取经,刚出长安城,就看到阿难与迦叶把佛祖的真经递过来了,是不是很省事?
CDN也是现在互联网中的一项重要基础设施除了基本的网络加速外还提供负载均衡、安全防护、边缘计算、跨运营商网络等功能能够成倍地“放大”源站服务器的服务能力很多云服务商都把CDN作为产品的一部分我也会在后面用一讲的篇幅来专门讲解CDN。
## 爬虫
前面说到过浏览器,它是一种用户代理,代替我们访问互联网。
但HTTP协议并没有规定用户代理后面必须是“真正的人类”它也完全可以是“机器人”这些“机器人”的正式名称就叫做“**爬虫**”Crawler实际上是一种可以自动访问Web资源的应用程序。
“爬虫”这个名字非常形象,它们就像是一只只不知疲倦的、辛勤的蚂蚁,在无边无际的网络上爬来爬去,不停地在网站间奔走,搜集抓取各种信息。
据估计互联网上至少有50%的流量都是由爬虫产生的,某些特定领域的比例还会更高,也就是说,如果你的网站今天的访问量是十万,那么里面至少有五六万是爬虫机器人,而不是真实的用户。
爬虫是怎么来的呢?
绝大多数是由各大搜索引擎“放”出来的,抓取网页存入庞大的数据库,再建立关键字索引,这样我们才能够在搜索引擎中快速地搜索到互联网角落里的页面。
爬虫也有不好的一面它会过度消耗网络资源占用服务器和带宽影响网站对真实数据的分析甚至导致敏感信息泄漏。所以又出现了“反爬虫”技术通过各种手段来限制爬虫。其中一项就是“君子协定”robots.txt约定哪些该爬哪些不该爬。
无论是“爬虫”还是“反爬虫”用到的基本技术都是两个一个是HTTP另一个就是HTML。
## HTML/WebService/WAF
到现在我已经说完了图中右边的五大部分而左边的HTML、WebService、WAF等由于与HTTP技术上实质关联不太大所以就简略地介绍一下不再过多展开。
**HTML**是HTTP协议传输的主要内容之一它描述了超文本页面用各种“标签”定义文字、图片等资源和排版布局最终由浏览器“渲染”出可视化页面。
HTML目前有两个主要的标准HTML4和HTML5。广义上的HTML通常是指HTML、JavaScript、CSS等前端技术的组合能够实现比传统静态页面更丰富的动态页面。
接下来是**Web** **Service**它的名字与Web Server很像但却是一个完全不同的东西。
Web Service是一种由W3C定义的应用服务开发规范使用client-server主从架构通常使用WSDL定义服务接口使用HTTP协议传输XML或SOAP消息也就是说它是**一个基于WebHTTP的服务架构技术**,既可以运行在内网,也可以在适当保护后运行在外网。
因为采用了HTTP协议传输数据所以在Web Service架构里服务器和客户端可以采用不同的操作系统或编程语言开发。例如服务器端用Linux+Java客户端用Windows+C#,具有跨平台跨语言的优点。
**WAF**是近几年比较“火”的一个词意思是“网络应用防火墙”。与硬件“防火墙”类似它是应用层面的“防火墙”专门检测HTTP流量是防护Web应用的安全技术。
WAF通常位于Web服务器之前可以阻止如SQL注入、跨站脚本等攻击目前应用较多的一个开源项目是ModSecurity它能够完全集成进Apache或Nginx。
## 小结
今天我详细介绍了与HTTP有关系的各种应用技术在这里简单小结一下要点。
1. 互联网上绝大部分资源都使用HTTP协议传输
1. 浏览器是HTTP协议里的请求方即User Agent
1. 服务器是HTTP协议里的应答方常用的有Apache和Nginx
1. CDN位于浏览器和服务器之间主要起到缓存加速的作用
1. 爬虫是另一类User Agent是自动访问网络资源的程序。
希望通过今天的讲解,你能够更好地理解这些概念,也利于后续的课程学习。
## 课下作业
1. 你觉得CDN在对待浏览器和爬虫时会有差异吗为什么
1. 你怎么理解WebService与Web Server这两个非常相似的词
欢迎你通过留言分享答案,与我和其他同学一起讨论。如果你觉得有所收获,欢迎你把文章分享给你的朋友。
<img src="https://static001.geekbang.org/resource/image/9a/5a/9ae4483ad53e403464869f227678cf5a.png" alt="unpreview">

View File

@@ -0,0 +1,148 @@
<audio id="audio" title="04 | HTTP世界全览与HTTP相关的各种协议" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/99/51/995cf58219a4e99589c7d58ffa66a451.mp3"></audio>
在上一讲中我介绍了与HTTP相关的浏览器、服务器、CDN、网络爬虫等应用技术。
今天要讲的则是比较偏向于理论的各种HTTP相关协议重点是TCP/IP、DNS、URI、HTTPS等希望能够帮你理清楚它们与HTTP的关系。
同样的,我还是画了一张详细的思维导图,你可以点击后仔细查看。
<img src="https://static001.geekbang.org/resource/image/1e/81/1e7533f765d2ede0abfab73cf6b57781.png" alt="">
## TCP/IP
TCP/IP协议是目前网络世界“事实上”的标准通信协议即使你没有用过也一定听说过因为它太著名了。
TCP/IP协议实际上是一系列网络通信协议的统称其中最核心的两个协议是**TCP**和**IP**其他的还有UDP、ICMP、ARP等等共同构成了一个复杂但有层次的协议栈。
这个协议栈有四层最上层是“应用层”最下层是“链接层”TCP和IP则在中间**TCP属于“传输层”IP属于“网际层”**。协议的层级关系模型非常重要,我会在下一讲中再专门讲解,这里先暂时放一放。
**IP协议**是“**I**nternet **P**rotocol”的缩写主要目的是解决寻址和路由问题以及如何在两点间传送数据包。IP协议使用“**IP地址**”的概念来定位互联网上的每一台计算机。可以对比一下现实中的电话系统你拿着的手机相当于互联网上的计算机而要打电话就必须接入电话网由通信公司给你分配一个号码这个号码就相当于IP地址。
现在我们使用的IP协议大多数是v4版地址是四个用“.”分隔的数字例如“192.168.0.1”总共有2^32大约42亿个可以分配的地址。看上去好像很多但互联网的快速发展让地址的分配管理很快就“捉襟见肘”。所以就又出现了v6版使用8组“:”分隔的数字作为地址容量扩大了很多有2^128个在未来的几十年里应该是足够用了。
**TCP协议**是“**T**ransmission **C**ontrol **P**rotocol”的缩写意思是“传输控制协议”它位于IP协议之上基于IP协议提供可靠的、字节流形式的通信是HTTP协议得以实现的基础。
“可靠”是指保证数据不丢失“字节流”是指保证数据完整所以在TCP协议的两端可以如同操作文件一样访问传输的数据就像是读写在一个密闭的管道里“流动”的字节。
在[第2讲](https://time.geekbang.org/column/article/98128)时我曾经说过HTTP是一个"传输协议"但它不关心寻址、路由、数据完整性等传输细节而要求这些工作都由下层来处理。因为互联网上最流行的是TCP/IP协议而它刚好满足HTTP的要求所以互联网上的HTTP协议就运行在了TCP/IP上HTTP也就可以更准确地称为“**HTTP over TCP/IP**”。
## DNS
在TCP/IP协议中使用IP地址来标识计算机数字形式的地址对于计算机来说是方便了但对于人类来说却既难以记忆又难以输入。
于是“**域名系统**”(**D**omain **N**ame **S**ystem出现了用有意义的名字来作为IP地址的等价替代。设想一下你是愿意记“95.211.80.227”这样枯燥的数字还是“nginx.org”这样的词组呢
在DNS中“域名”Domain Name又称为“主机名”Host为了更好地标记不同国家或组织的主机让名字更好记所以被设计成了一个有层次的结构。
域名用“.”分隔成多个单词级别从左到右逐级升高最右边的被称为“顶级域名”。对于顶级域名可能你随口就能说出几个例如表示商业公司的“com”、表示教育机构的“edu”表示国家的“cn”“uk”等买火车票时的域名还记得吗是“www.12306.cn”。
<img src="https://static001.geekbang.org/resource/image/36/b3/36b6a41da6e9abc2fc28ee9a305f48b3.jpg" alt="unpreview">
但想要使用TCP/IP协议来通信仍然要使用IP地址所以需要把域名做一个转换“映射”到它的真实IP这就是所谓的“**域名解析**”。
继续用刚才的打电话做个比喻你想要打电话给小明但不知道电话号码就得在手机里的号码簿里一项一项地找直到找到小明那一条记录然后才能查到号码。这里的“小明”就相当于域名而“电话号码”就相当于IP地址这个查找的过程就是域名解析。
域名解析的实际操作要比刚才的例子复杂很多因为互联网上的电脑实在是太多了。目前全世界有13组根DNS服务器下面再有许多的顶级DNS、权威DNS和更小的本地DNS逐层递归地实现域名查询。
HTTP协议中并没有明确要求必须使用DNS但实际上为了方便访问互联网上的Web服务器通常都会使用DNS来定位或标记主机名间接地把DNS与HTTP绑在了一起。
## URI/URL
有了TCP/IP和DNS是不是我们就可以任意访问网络上的资源了呢
还不行DNS和IP地址只是标记了互联网上的主机但主机上有那么多文本、图片、页面到底要找哪一个呢就像小明管理了一大堆文档你怎么告诉他是哪个呢
所以就出现了URI**U**niform **R**esource **I**dentifier中文名称是 **统一资源标识符**,使用它就能够唯一地标记互联网上资源。
URI另一个更常用的表现形式是URL**U**niform **R**esource **L**ocator **统一资源定位符**也就是我们俗称的“网址”它实际上是URI的一个子集不过因为这两者几乎是相同的差异不大所以通常不会做严格的区分。
我就拿Nginx网站来举例看一下URI是什么样子的。
```
http://nginx.org/en/download.html
```
你可以看到URI主要有三个基本的部分构成
1. 协议名即访问该资源应当使用的协议在这里是“http”
1. 主机名即互联网上主机的标记可以是域名或IP地址在这里是“nginx.org”
1. 路径:即资源在主机上的位置,使用“/”分隔多级目录,在这里是“/en/download.html”。
还是用打电话来做比喻你通过电话簿找到了小明让他把昨天做好的宣传文案快递过来。那么这个过程中你就完成了一次URI资源访问“小明”就是“主机名”“昨天做好的宣传文案”就是“路径”而“快递”就是你要访问这个资源的“协议名”。
## HTTPS
在TCP/IP、DNS和URI的“加持”之下HTTP协议终于可以自由地穿梭在互联网世界里顺利地访问任意的网页了真的是“好生快活”。
但且慢,互联网上不仅有“美女”,还有很多的“野兽”。
假设你打电话找小明要一份广告创意,很不幸,电话被商业间谍给窃听了,他立刻动用种种手段偷窃了你的快递,就在你还在等包裹的时候,他抢先发布了这份广告,给你的公司造成了无形或有形的损失。
有没有什么办法能够防止这种情况的发生呢?确实有。你可以使用“加密”的方法,比如这样打电话:
>
<p>你:“喂,小明啊,接下来我们改用火星文通话吧。”<br>
小明:“好啊好啊,就用火星文吧。”<br>
你:“巴拉巴拉巴拉巴拉……”<br>
小明:“巴拉巴拉巴拉巴拉……”</p>
如果你和小明说的火星文只有你们两个才懂,那么即使窃听到了这段谈话,他也不会知道你们到底在说什么,也就无从破坏你们的通话过程。
HTTPS就相当于这个比喻中的“火星文”它的全称是“**HTTP over SSL/TLS**”也就是运行在SSL/TLS协议上的HTTP。
注意它的名字这里是SSL/TLS而不是TCP/IP它是一个负责加密通信的安全协议建立在TCP/IP之上所以也是个可靠的传输协议可以被用作HTTP的下层。
因为HTTPS相当于“HTTP+SSL/TLS+TCP/IP”其中的“HTTP”和“TCP/IP”我们都已经明白了只要再了解一下SSL/TLSHTTPS也就能够轻松掌握。
SSL的全称是“**S**ecure **S**ocket **L**ayer”由网景公司发明当发展到3.0时被标准化改名为TLS即“**T**ransport **L**ayer **S**ecurity”但由于历史的原因还是有很多人称之为SSL/TLS或者直接简称为SSL。
SSL使用了许多密码学最先进的研究成果综合了对称加密、非对称加密、摘要算法、数字签名、数字证书等技术能够在不安全的环境中为通信的双方创建出一个秘密的、安全的传输通道为HTTP套上一副坚固的盔甲。
你可以在今后上网时留心看一下浏览器地址栏如果有一个小锁头标志那就表明网站启用了安全的HTTPS协议而URI里的协议名也从“http”变成了“https”。
## 代理
代理Proxy是HTTP协议中请求方和应答方中间的一个环节作为“中转站”既可以转发客户端的请求也可以转发服务器的应答。
代理有很多的种类,常见的有:
1. 匿名代理:完全“隐匿”了被代理的机器,外界看到的只是代理服务器;
1. 透明代理:顾名思义,它在传输过程中是“透明开放”的,外界既知道代理,也知道客户端;
1. 正向代理:靠近客户端,代表客户端向服务器发送请求;
1. 反向代理:靠近服务器端,代表服务器响应客户端的请求;
上一讲提到的CDN实际上就是一种代理它代替源站服务器响应客户端的请求通常扮演着透明代理和反向代理的角色。
由于代理在传输过程中插入了一个“中间层”,所以可以在这个环节做很多有意思的事情,比如:
1. 负载均衡:把访问请求均匀分散到多台机器,实现访问集群化;
1. 内容缓存:暂存上下行的数据,减轻后端的压力;
1. 安全防护隐匿IP,使用WAF等工具抵御网络攻击保护被代理的机器
1. 数据处理:提供压缩、加密等额外的功能。
关于HTTP的代理还有一个特殊的“代理协议”proxy protocol它由知名的代理软件HAProxy制订但并不是RFC标准我也会在之后的课程里专门讲解。
## 小结
这次我介绍了与HTTP相关的各种协议在这里简单小结一下今天的内容。
1. TCP/IP是网络世界最常用的协议HTTP通常运行在TCP/IP提供的可靠传输基础上
1. DNS域名是IP地址的等价替代需要用域名解析实现到IP地址的映射
1. URI是用来标记互联网上资源的一个名字由“协议名+主机名+路径”构成俗称URL
1. HTTPS相当于“HTTP+SSL/TLS+TCP/IP”为HTTP套了一个安全的外壳
1. 代理是HTTP传输过程中的“中转站”可以实现缓存加速、负载均衡等功能。
经过这两讲的学习相信你应该对HTTP有了一个比较全面的了解虽然还不是很深入但已经为后续的学习扫清了障碍。
## 课下作业
1. DNS与URI有什么关系
1. 在讲**代理**时我特意没有举例说明,你能够用引入一个“小强”的角色,通过打电话来比喻一下吗?
欢迎你通过留言分享答案,与我和其他同学一起讨论。如果你觉得有所收获,欢迎你把文章分享给你的朋友。
<img src="https://static001.geekbang.org/resource/image/4e/56/4eab55dc3600071330e088b40cae4856.png" alt="unpreview">

View File

@@ -0,0 +1,147 @@
<audio id="audio" title="05 | 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/26/de/26833f97618434f8a57449e97f4da3de.mp3"></audio>
在上一讲中我简单提到了TCP/IP协议它是HTTP协议的下层协议负责具体的数据传输工作。并且还特别说了TCP/IP协议是一个“**有层次的协议栈**”。
在工作中你一定经常听别人谈起什么“四层负载均衡”“七层负载均衡”,什么“二层转发”“三层路由”,那么你真正理解这些层次的含义吗?
网络分层的知识教科书上都有,但很多都是“泛泛而谈”,只有“学术价值”,于是就容易和实际应用“脱节”,造成的后果就是“似懂非懂”,真正用的时候往往会“一头雾水”。
所以今天我就从HTTP应用的角度帮你把这些模糊的概念弄清楚。
## TCP/IP网络分层模型
还是先从TCP/IP协议开始讲起一是因为它非常经典二是因为它是目前事实上的网络通信标准研究它的实用价值最大。
TCP/IP当初的设计者真的是非常聪明创造性地提出了“**分层**”的概念,把复杂的网络通信划分出多个层次,再给每一个层次分配不同的职责,层次内只专心做自己的事情就好,用“分而治之”的思想把一个“大麻烦”拆分成了数个“小麻烦”,从而解决了网络通信的难题。
你应该对TCP/IP的协议栈有所了解吧这里我再贴一下层次图。
<img src="https://static001.geekbang.org/resource/image/2b/03/2b8fee82b58cc8da88c74a33f2146703.png" alt="">
TCP/IP协议总共有四层就像搭积木一样每一层需要下层的支撑同时又支撑着上层任何一层被抽掉都可能会导致整个协议栈坍塌。
我们来仔细地看一下这个精巧的积木架构,注意它的层次顺序是“**从下往上**”数的,所以第一层就是最下面的一层。
第一层叫“**链接层**”link layer负责在以太网、WiFi这样的底层网络上发送原始数据包工作在网卡这个层次使用MAC地址来标记网络上的设备所以有时候也叫MAC层。
第二层叫“**网际层**”或者“**网络互连层**”internet layerIP协议就处在这一层。因为IP协议定义了“IP地址”的概念所以就可以在“链接层”的基础上用IP地址取代MAC地址把许许多多的局域网、广域网连接成一个虚拟的巨大网络在这个网络里找设备时只要把IP地址再“翻译”成MAC地址就可以了。
第三层叫“**传输层**”transport layer这个层次协议的职责是保证数据在IP地址标记的两点之间“可靠”地传输是TCP协议工作的层次另外还有它的一个“小伙伴”UDP。
TCP是一个有状态的协议需要先与对方建立连接然后才能发送数据而且保证数据不丢失不重复。而UDP则比较简单它无状态不用事先建立连接就可以任意发送数据但不保证数据一定会发到对方。两个协议的另一个重要区别在于数据的形式。TCP的数据是连续的“字节流”有先后顺序而UDP则是分散的小数据包是顺序发乱序收。
关于TCP和UDP可以展开讨论的话题还有很多比如最经典的“三次握手”和“四次挥手”一时半会很难说完好在与HTTP的关系不是太大以后遇到了再详细讲解。
协议栈的第四层叫“**应用层**”application layer由于下面的三层把基础打得非常好所以在这一层就“百花齐放”了有各种面向具体应用的协议。例如Telnet、SSH、FTP、SMTP等等当然还有我们的HTTP。
MAC层的传输单位是帧frameIP层的传输单位是包packetTCP层的传输单位是段segmentHTTP的传输单位则是消息或报文message。但这些名词并没有什么本质的区分可以统称为数据包。
## OSI网络分层模型
看完TCP/IP协议栈你可能要问了“它只有四层那常说的七层怎么没见到呢
别着急,这就是今天要说的第二个网络分层模型:**OSI**,全称是“**开放式系统互联通信参考模型**”Open System Interconnection Reference Model
TCP/IP发明于1970年代当时除了它还有很多其他的网络协议整个网络世界比较混乱。
这个时候国际标准组织ISO注意到了这种现象感觉“野路子”太多就想要来个“大一统”。于是设计出了一个新的网络分层模型想用这个新框架来统一既存的各种网络协议。
OSI模型分成了七层部分层次与TCP/IP很像从下到上分别是
<img src="https://static001.geekbang.org/resource/image/3a/dc/3abcf1462621ff86758a8d9571c07cdc.png" alt="">
1. 第一层:物理层,网络的物理形式,例如电缆、光纤、网卡、集线器等等;
1. 第二层数据链路层它基本相当于TCP/IP的链接层
1. 第三层网络层相当于TCP/IP里的网际层
1. 第四层传输层相当于TCP/IP里的传输层
1. 第五层:会话层,维护网络中的连接状态,即保持会话和同步;
1. 第六层:表示层,把数据转换为合适、可理解的语法和语义;
1. 第七层:应用层,面向具体的应用传输数据。
至此,我们常说的“四层”“七层”就出现了。
不过国际标准组织心里也很清楚TCP/IP等协议已经在许多网络上实际运行再推翻重来是不可能的。所以OSI分层模型在发布的时候就明确地表明是一个“参考”不是强制标准意思就是说“你们以后该干什么还干什么我不管但面子上还是要按照我说的来”。
但OSI模型也是有优点的。对比一下就可以看出TCP/IP是一个纯软件的栈没有网络应有的最根基的电缆、网卡等物理设备的位置。而OSI则补足了这个缺失在理论层面上描述网络更加完整。
还有一个重要的形式上的优点OSI为每一层标记了明确了编号最底层是一层最上层是七层而TCP/IP的层次从来只有名字而没有编号。显然在交流的时候说“七层”要比“应用层”更简单快捷特别是英文对比一下“Layer seven”与“application layer”。
综合以上几点在OSI模型之后“四层”“七层”这样的说法就逐渐流行开了。不过在实际工作中你一定要注意这种说法只是“理论上”的层次并不是与现实完全对应。
## 两个分层模型的映射关系
现在我们有了两个网络分层模型TCP/IP和OSI新的问题又出现了一个是四层模型一个是七层模型这两者应该如何互相映射或者说互相解释呢
好在OSI在设计之初就参考了TCP/IP等多个协议可以比较容易但不是很精确地实现对应关系。
<img src="https://static001.geekbang.org/resource/image/9d/94/9d9b3c9274465c94e223676b6d434194.png" alt="">
1. 第一层物理层TCP/IP里无对应
1. 第二层数据链路层对应TCP/IP的链接层
1. 第三层网络层对应TCP/IP的网际层
1. 第四层传输层对应TCP/IP的传输层
1. 第五、六、七层统一对应到TCP/IP的应用层。
所以你看,这就是“理想与现实”之间的矛盾。理想很美好,有七层,但现实很残酷,只有四层,“多余”的五层、六层就这样“消失”了。
但这也有一定的实际原因。
OSI的分层模型在四层以上分的太细而TCP/IP实际应用时的会话管理、编码转换、压缩等和具体应用经常联系的很紧密很难分开。例如HTTP协议就同时包含了连接管理和数据格式定义。
到这里,你应该能够明白一开始那些“某某层”的概念了。
所谓的“四层负载均衡”就是指工作在传输层上基于TCP/IP协议的特性例如IP地址、端口号等实现对后端服务器的负载均衡。
所谓的“七层负载均衡”就是指工作在应用层上看到的是HTTP协议解析HTTP报文里的URI、主机名、资源类型等数据再用适当的策略转发给后端服务器。
## TCP/IP协议栈的工作方式
TCP/IP协议栈是如何工作的呢
你可以把HTTP利用TCP/IP协议栈传输数据想象成一个发快递的过程。
假设你想把一件毛绒玩具送给朋友但你要先拿个塑料袋套一下这件玩具就相当于HTTP协议里要传输的内容比如HTML然后HTTP协议为它加一个HTTP专用附加数据。
你把玩具交给快递小哥为了保护货物他又加了层包装再贴了个标签相当于在TCP层给数据再次打包加上了TCP头。
接着快递小哥下楼把包裹放进了三轮车里运到集散点然后再装进更大的卡车里相当于在IP层、MAC层对TCP数据包加上了IP头、MAC头。
之后经过漫长的运输包裹到达目的地要卸货再放进另一位快递员的三轮车就是在IP层、MAC层传输后拆包。
快递员到了你朋友的家门口撕掉标签去除了TCP层的头你朋友再拆掉塑料袋包装也就是HTTP头最后就拿到了玩具也就是真正的HTML页面。
这个比喻里省略了很多TCP/IP协议里的细节比如建连、路由、数据切分与重组、错误检查等但核心的数据传输过程是差不多的。
HTTP协议的传输过程就是这样通过协议栈逐层向下每一层都添加本层的专有数据层层打包然后通过下层发送出去。
接收数据则是相反的操作,从下往上穿过协议栈,逐层拆包,每层去掉本层的专有头,上层就会拿到自己的数据。
但下层的传输过程对于上层是完全“透明”的上层也不需要关心下层的具体实现细节所以就HTTP层次来看它不管下层是不是TCP/IP协议看到的只是一个可靠的传输链路只要把数据加上自己的头对方就能原样收到。
我为这个过程画了一张图,你可以对照着加深理解。
<img src="https://static001.geekbang.org/resource/image/70/6f/70bc19acacf2245fa841349f15cb7a6f.png" alt="">
## 小结
这次我们学习了HTTP所在的网络分层模型它是工作中常用的交流语言在这里简单小结一下今天的内容。
1. TCP/IP分为四层核心是二层的IP和三层的TCPHTTP在第四层
1. OSI分为七层基本对应TCP/IPTCP在第四层HTTP在第七层
1. OSI可以映射到TCP/IP但这期间一、五、六层消失了
1. 日常交流的时候我们通常使用OSI模型用四层、七层等术语
1. HTTP利用TCP/IP协议栈逐层打包再拆包实现了数据传输但下面的细节并不可见。
有一个辨别四层和七层比较好的(但不是绝对的)小窍门,“**两个凡是**”:凡是由操作系统负责处理的就是四层或四层以下,否则,凡是需要由应用程序(也就是你自己写代码)负责处理的就是七层。
## 课下作业
1. 你能用自己的话解释一下“二层转发”“三层路由”吗?
1. 你认为上一讲中的DNS协议位于哪一层呢
1. 你认为CDN工作在那一层呢
欢迎你把自己的答案写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
<img src="https://static001.geekbang.org/resource/image/30/92/3010b80124bca2f3a91a726713e9ac92.png" alt="unpreview">

View File

@@ -0,0 +1,136 @@
<audio id="audio" title="06 | 域名里有哪些门道?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/81/3e/81cf8701700965c6fea30f406497bc3e.mp3"></audio>
在上一讲里我们学习了HTTP协议使用的TCP/IP协议栈知道了HTTP协议是运行在TCP/IP上的。
IP协议的职责是“网际互连”它在MAC层之上使用IP地址把MAC编号转换成了四位数字这就对物理网卡的MAC地址做了一层抽象发展出了许多的“新玩法”。
例如分为A、B、C、D、E五种类型公有地址和私有地址掩码分割子网等。只要每个小网络在IP地址这个概念上达成一致不管它在MAC层有多大的差异都可以接入TCP/IP协议栈最终汇合进整个互联网。
但接入互联网的计算机越来越多IP地址的缺点也就暴露出来了最主要的是它“对人不友好”虽然比MAC的16进制数要好一点但还是难于记忆和输入。
怎么解决这个问题呢?
那就“以其人之道还治其人之身”在IP地址之上再来一次抽象把数字形式的IP地址转换成更有意义更好记的名字在字符串的层面上再增加“新玩法”。于是DNS域名系统就这么出现了。
## 域名的形式
在第4讲曾经说过域名是一个有层次的结构是一串用“.”分隔的多个单词,最右边的被称为“顶级域名”,然后是“二级域名”,层级关系向左依次降低。
最左边的是主机名通常用来表明主机的用途比如“www”表示提供万维网服务、“mail”表示提供邮件服务不过这也不是绝对的名字的关键是要让我们容易记忆。
看一下极客时间的域名“time.geekbang.org”这里的“org”就是顶级域名“geekbang”是二级域名“time”则是主机名。使用这个域名DNS就会把它转换成相应的IP地址你就可以访问极客时间的网站了。
域名不仅能够代替IP地址还有许多其他的用途。
在Apache、Nginx这样的Web服务器里域名可以用来标识虚拟主机决定由哪个虚拟主机来对外提供服务比如在Nginx里就会使用“server_name”指令
```
server {
listen 80; #监听80端口
server_name time.geekbang.org; #主机名是time.geekbang.org
...
}
```
域名本质上还是个名字空间系统,使用多级域名就可以划分出不同的国家、地区、组织、公司、部门,每个域名都是独一无二的,可以作为一种身份的标识。
举个例子吧假设A公司里有个小明B公司里有个小强于是他们就可以分别说是“小明.A公司”“小强.B公司”即使B公司里也有个小明也不怕可以标记为“小明.B公司”很好地解决了重名问题。
因为这个特性域名也被扩展到了其他应用领域比如Java的包机制就采用域名作为命名空间只是它使用了反序。如果极客时间要开发Java应用那么它的包名可能就是“org.geekbang.time”。
而XML里使用URI作为名字空间也是间接使用了域名。
## 域名的解析
就像IP地址必须转换成MAC地址才能访问主机一样域名也必须要转换成IP地址这个过程就是“**域名解析**”。
目前全世界有几亿个站点有几十亿网民而每天网络上发生的HTTP流量更是天文数字。这些请求绝大多数都是基于域名来访问网站的所以DNS就成了互联网的重要基础设施必须要保证域名解析稳定可靠、快速高效。
DNS的核心系统是一个三层的树状、分布式服务基本对应域名的结构
1. 根域名服务器Root DNS Server管理顶级域名服务器返回“com”“net”“cn”等顶级域名服务器的IP地址
1. 顶级域名服务器Top-level DNS Server管理各自域名下的权威域名服务器比如com顶级域名服务器可以返回apple.com域名服务器的IP地址
1. 权威域名服务器Authoritative DNS Server管理自己域名下主机的IP地址比如apple.com权威域名服务器可以返回www.apple.com的IP地址。
<img src="https://static001.geekbang.org/resource/image/6b/f2/6b020454987543efdd1cf6ddec784bf2.png" alt="">
在这里根域名服务器是关键它必须是众所周知的否则下面的各级服务器就无从谈起了。目前全世界共有13组根域名服务器又有数百台的镜像保证一定能够被访问到。
有了这个系统以后任何一个域名都可以在这个树形结构里从顶至下进行查询就好像是把域名从右到左顺序走了一遍最终就获得了域名对应的IP地址。
例如你要访问“www.apple.com”就要进行下面的三次查询
1. 访问根域名服务器它会告诉你“com”顶级域名服务器的地址
1. 访问“com”顶级域名服务器它再告诉你“apple.com”域名服务器的地址
1. 最后访问“apple.com”域名服务器就得到了“www.apple.com”的地址。
虽然核心的DNS系统遍布全球服务能力很强也很稳定但如果全世界的网民都往这个系统里挤即使不挤瘫痪了访问速度也会很慢。
所以在核心DNS系统之外还有两种手段用来减轻域名解析的压力并且能够更快地获取结果基本思路就是“**缓存**”。
首先许多大公司、网络运行商都会建立自己的DNS服务器作为用户DNS查询的代理代替用户访问核心DNS系统。这些“野生”服务器被称为“非权威域名服务器”可以缓存之前的查询结果如果已经有了记录就无需再向根服务器发起查询直接返回对应的IP地址。
这些DNS服务器的数量要比核心系统的服务器多很多而且大多部署在离用户很近的地方。比较知名的DNS有Google的“8.8.8.8”Microsoft的“4.2.2.1”还有CloudFlare的“1.1.1.1”等等。
其次操作系统里也会对DNS解析结果做缓存如果你之前访问过“www.apple.com”那么下一次在浏览器里再输入这个网址的时候就不会再跑到DNS那里去问了直接在操作系统里就可以拿到IP地址。
另外操作系统里还有一个特殊的“主机映射”文件通常是一个可编辑的文本在Linux里是“/etc/hosts”在Windows里是“C:\WINDOWS\system32\drivers\etc\hosts”如果操作系统在缓存里找不到DNS记录就会找这个文件。
有了上面的“野生”DNS服务器、操作系统缓存和hosts文件后很多域名解析的工作就都不用“跋山涉水”了直接在本地或本机就能解决不仅方便了用户也减轻了各级DNS服务器的压力效率就大大提升了。
下面的这张图比较完整地表示了现在的DNS架构。
<img src="https://static001.geekbang.org/resource/image/e5/ac/e51df3245609880641043af65bba94ac.png" alt="">
在Nginx里有这么一条配置指令“resolver”它就是用来配置DNS服务器的如果没有它那么Nginx就无法查询域名对应的IP也就无法反向代理到外部的网站。
```
resolver 8.8.8.8 valid=30s; #指定Google的DNS缓存30秒
```
## 域名的“新玩法”
有了域名又有了可以稳定工作的解析系统于是我们就可以实现比IP地址更多的“新玩法”了。
第一种也是最简单的“重定向”。因为域名代替了IP地址所以可以让对外服务的域名不变而主机的IP地址任意变动。当主机有情况需要下线、迁移时可以更改DNS记录让域名指向其他的机器。
比如你有一台“buy.tv”的服务器要临时停机维护那你就可以通知DNS服务器“我这个buy.tv域名的地址变了啊原先是1.2.3.4现在是5.6.7.8麻烦你改一下。”DNS于是就修改内部的IP地址映射关系之后再有访问buy.tv的请求就不走1.2.3.4这台主机改由5.6.7.8来处理,这样就可以保证业务服务不中断。
第二种因为域名是一个名字空间所以可以使用bind9等开源软件搭建一个在内部使用的DNS作为名字服务器。这样我们开发的各种内部服务就都用域名来标记比如数据库服务都用域名“mysql.inner.app”商品服务都用“goods.inner.app”发起网络通信时也就不必再使用写死的IP地址了可以直接用域名而且这种方式也兼具了第一种“玩法”的优势。
第三种“玩法”包含了前两种,也就是基于域名实现的负载均衡。
这种“玩法”也有两种方式,两种方式可以混用。
第一种方式因为域名解析可以返回多个IP地址所以一个域名可以对应多台主机客户端收到多个IP地址后就可以自己使用轮询算法依次向服务器发起请求实现负载均衡。
第二种方式域名解析可以配置内部的策略返回离客户端最近的主机或者返回当前服务质量最好的主机这样在DNS端把请求分发到不同的服务器实现负载均衡。
前面我们说的都是可信的DNS如果有一些不怀好意的DNS那么它也可以在域名这方面“做手脚”弄一些比较“恶意”的“玩法”举两个例子
- “域名屏蔽”对域名直接不解析返回错误让你无法拿到IP地址也就无法访问网站
- “域名劫持”也叫“域名污染”你要访问A网站但DNS给了你B网站。
好在互联网上还是好人多而且DNS又是互联网的基础设施这些“恶意DNS”并不多见你上网的时候不需要太过担心。
## 小结
这次我们学习了与HTTP协议有重要关系的域名和DNS在这里简单小结一下今天的内容
1. 域名使用字符串来代替IP地址方便用户记忆本质上一个名字空间系统
1. DNS就像是我们现实世界里的电话本、查号台统管着互联网世界里的所有网站是一个“超级大管家”
1. DNS是一个树状的分布式查询系统但为了提高查询效率外围有多级的缓存
1. 使用DNS可以实现基于域名的负载均衡既可以在内网也可以在外网。
## 课下作业
1. 在浏览器地址栏里随便输入一个不存在的域名比如就叫“www.不存在.com”试着解释一下它的DNS解析过程。
1. 如果因为某些原因DNS失效或者出错了会出现什么后果
欢迎你把自己的答案写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
<img src="https://static001.geekbang.org/resource/image/78/36/7838e0e705864ddfeacc79e0aeb8f236.png" alt="unpreview">

View File

@@ -0,0 +1,155 @@
<audio id="audio" title="07 | 自己动手搭建HTTP实验环境" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/5a/80/5a81d350ff30475e95ccc4261b90b580.mp3"></audio>
这一讲是“破冰篇”的最后一讲我会先简单地回顾一下之前的内容然后在Windows系统上实际操作用几个应用软件搭建出一个“最小化”的HTTP实验环境方便后续的“基础篇”“进阶篇”“安全篇”的学习。
## “破冰篇”回顾
HTTP协议诞生于30年前设计之初的目的是用来传输纯文本数据。但由于形式灵活搭配URI、HTML等技术能够把互联网上的资源都联系起来构成一个复杂的超文本系统让人们自由地获取信息所以得到了迅猛发展。
HTTP有多个版本目前应用的最广泛的是HTTP/1.1它几乎可以说是整个互联网的基石。但HTTP/1.1的性能难以满足如今的高流量网站于是又出现了HTTP/2和HTTP/3。不过这两个新版本的协议还没有完全推广开。在可预见的将来HTTP/1.1还会继续存在下去。
HTTP翻译成中文是“超文本传输协议”是一个应用层的协议通常基于TCP/IP能够在网络的任意两点之间传输文字、图片、音频、视频等数据。
HTTP协议中的两个端点称为**请求方**和**应答方**。请求方通常就是Web浏览器也叫user agent应答方是Web服务器存储着网络上的大部分静态或动态的资源。
在浏览器和服务器之间还有一些“中间人”的角色如CDN、网关、代理等它们也同样遵守HTTP协议可以帮助用户更快速、更安全地获取资源。
HTTP协议不是一个孤立的协议需要下层很多其他协议的配合。最基本的是TCP/IP实现寻址、路由和可靠的数据传输还有DNS协议实现对互联网上主机的定位查找。
对HTTP更准确的称呼是“**HTTP over TCP/IP**”,而另一个“**HTTP over SSL/TLS**”就是增加了安全功能的HTTPS。
## 软件介绍
常言道“实践出真知”又有俗语“光说不练是假把式”。要研究HTTP协议最好有一个实际可操作、可验证的环境通过实际的数据、现象来学习肯定要比单纯的“动嘴皮子”效果要好的多。
现成的环境当然有只要能用浏览器上网就会有HTTP协议就可以进行实验。但现实的网络环境又太复杂了有很多无关的干扰因素这些“噪音”会“淹没”真正有用的信息。
所以,我给你的建议是:搭建一个“**最小化**”的环境在这个环境里仅有HTTP协议的两个端点请求方和应答方去除一切多余的环节从而可以抓住重点快速掌握HTTP的本质。
<img src="https://static001.geekbang.org/resource/image/85/0b/85cadf90dc96cf413afaf8668689ef0b.png" alt="">
简单说一下这个“最小化”环境用到的应用软件:
- Wireshark
- Chrome/Firefox
- Telnet
- OpenResty
**Wireshark**是著名的网络抓包工具能够截获在TCP/IP协议栈中传输的所有流量并按协议类型、地址、端口等任意过滤功能非常强大是学习网络协议的必备工具。
它就像是网络世界里的一台“高速摄像机”,把只在一瞬间发生的网络传输过程如实地“拍摄”下来,事后再“慢速回放”,让我们能够静下心来仔细地分析那一瞬到底发生了什么。
**Chrome**是Google开发的浏览器是目前的主流浏览器之一。它不仅上网方便也是一个很好的调试器对HTTP/1.1、HTTPS、HTTP/2、QUIC等的协议都支持得非常好用F12打开“开发者工具”还可以非常详细地观测HTTP传输全过程的各种数据。
如果你更习惯使用**Firefox**那也没问题其实它和Chrome功能上都差不太多选择自己喜欢的就好。
与Wireshark不同Chrome和Firefox属于“事后诸葛亮”不能观测HTTP传输的过程只能看到结果。
**Telnet**是一个经典的虚拟终端基于TCP协议远程登录主机我们可以使用它来模拟浏览器的行为连接服务器后手动发送HTTP请求把浏览器的干扰也彻底排除能够从最原始的层面去研究HTTP协议。
**OpenResty**你可能比较陌生它是基于Nginx的一个“强化包”里面除了Nginx还有一大堆有用的功能模块不仅支持HTTP/HTTPS还特别集成了脚本语言Lua简化Nginx二次开发方便快速地搭建动态网关更能够当成应用容器来编写业务逻辑。
选择OpenResty而不直接用Nginx的原因是它相当于Nginx的“超集”功能更丰富安装部署更方便。我也会用Lua编写一些服务端脚本实现简单的Web服务器响应逻辑方便实验。
## 安装过程
这个“最小化”环境的安装过程也比较简单,大约只需要你半个小时不到的时间就能搭建完成。
我在GitHub上为本专栏开了一个项目[http_study](https://github.com/chronolaw/http_study.git)可以直接用“git clone”下载或者去Release页面下载打好的[压缩包](https://github.com/chronolaw/http_study/releases)。
我使用的操作环境是Windows 10如果你用的是Mac或者Linux可以用VirtualBox等虚拟机软件安装一个Windows虚拟机再在里面操作或者可以到“答疑篇”的[Linux/Mac实验环境搭建](https://time.geekbang.org/column/article/146833)中查看搭建方法)。
首先你要获取**最新**的http_study项目源码假设clone或解压的目录是“D:\http_study”操作完成后大概是下图这个样子。
<img src="https://static001.geekbang.org/resource/image/86/ee/862511b8ef87f78218631d832927bcee.png" alt="">
Chrome和WireShark的安装比较简单一路按“下一步”就可以了。版本方面使用最新的就好我的版本可能不是最新的Chrome是73WireShark是3.0.0。
Windows 10自带Telnet不需要安装但默认是不启用的需要你稍微设置一下。
打开Windows的设置窗口搜索“Telnet”就会找到“启用或关闭Windows功能”在这个窗口里找到“Telnet客户端”打上对钩就可以了可以参考截图。
<img src="https://static001.geekbang.org/resource/image/1a/47/1af035861c4fd33cb42005eaa1f5f247.png" alt="">
接下来我们要安装OpenResty去它的[官网](http://openresty.org)点击左边栏的“Download”进入下载页面下载适合你系统的版本这里我下载的是64位的1.15.8.1包的名字是“openresty-1.15.8.1-win64.zip”
<img src="https://static001.geekbang.org/resource/image/ee/0a/ee7016fecd79919de550677af32f740a.png" alt="">
然后要注意你必须把OpenResty的压缩包解压到刚才的“D:\http_study”目录里并改名为“openresty”。
<img src="https://static001.geekbang.org/resource/image/5a/b5/5acb89c96041f91bbc747b7e909fd4b5.png" alt="">
安装工作马上就要完成了为了能够让浏览器能够使用DNS域名访问我们的实验环境还要改一下本机的hosts文件位置在“C:\WINDOWS\system32\drivers\etc”在里面添加三行本机IP地址到测试域名的映射你也可以参考GitHub项目里的hosts文件这就相当于在一台物理实机上“托管”了三个虚拟主机。
```
127.0.0.1 www.chrono.com
127.0.0.1 www.metroid.net
127.0.0.1 origin.io
```
注意修改hosts文件需要管理员权限直接用记事本编辑是不行的可以切换管理员身份或者改用其他高级编辑器比如Notepad++,而且改之前最好做个备份。
到这里我们的安装工作就完成了之后你就可以用Wireshark、Chrome、Telnet在这个环境里随意“折腾”弄坏了也不要紧只要把目录删除再来一遍操作就能复原。
## 测试验证
实验环境搭建完了,但还需要把它运行起来,做一个简单的测试验证,看是否运转正常。
首先我们要启动Web服务器也就是OpenResty。
在http_study的“www”目录下有四个批处理文件分别是
<img src="https://static001.geekbang.org/resource/image/e5/da/e5d35bb94c46bfaaf8ce5c143b2bb2da.png" alt="">
- start启动OpenResty服务器
- stop停止OpenResty服务器
- reload重启OpenResty服务器
- list列出已经启动的OpenResty服务器进程。
使用鼠标双击“start”批处理文件就会启动OpenResty服务器在后台运行这个过程可能会有Windows防火墙的警告选择“允许”即可。
运行后鼠标双击“list”可以查看OpenResty是否已经正常启动应该会有两个nginx.exe的后台进程大概是下图的样子。
<img src="https://static001.geekbang.org/resource/image/db/1d/dba34b8a38e98bef92289315db29ee1d.png" alt="">
有了Web服务器后接下来我们要运行Wireshark开始抓包。
因为我们的实验环境运行在本机的127.0.0.1上也就是loopback“环回”地址。所以在Wireshark里要选择“Npcap loopback Adapter”过滤器选择“HTTP TCP port(80)”即只抓取HTTP相关的数据包。鼠标双击开始界面里的“Npcap loopback Adapter”即可开始抓取本机上的网络数据。
<img src="https://static001.geekbang.org/resource/image/12/c4/128d8a5ed9cdd666dbfa4e17fd39afc4.png" alt="">
然后我们打开Chrome在地址栏输入“`http://localhost`访问刚才启动的OpenResty服务器就会看到一个简单的欢迎界面如下图所示。
<img src="https://static001.geekbang.org/resource/image/d7/88/d7f12d4d480d7100cd9804d2b16b8a88.png" alt="">
这时再回头去看Wireshark应该会显示已经抓到了一些数据就可以用鼠标点击工具栏里的“停止捕获”按钮告诉Wireshark“到此为止”不再继续抓包。
<img src="https://static001.geekbang.org/resource/image/f7/79/f7d05a3939d81742f18d2da7a1883179.png" alt="">
至于这些数据是什么,表示什么含义,我会在下一讲再详细介绍。
如果你能够在自己的电脑上走到这一步就说明“最小化”的实验环境已经搭建成功了不要忘了实验结束后运行批处理“stop”停止OpenResty服务器。
## 小结
这次我们学习了如何在自己的电脑上搭建HTTP实验环境在这里简单小结一下今天的内容。
1. 现实的网络环境太复杂有很多干扰因素搭建“最小化”的环境可以快速抓住重点掌握HTTP的本质
1. 我们选择Wireshark作为抓包工具捕获在TCP/IP协议栈中传输的所有流量
1. 我们选择Chrome或Firefox浏览器作为HTTP协议中的user agent
1. 我们选择OpenResty作为Web服务器它是一个Nginx的“强化包”功能非常丰富
1. Telnet是一个命令行工具可用来登录主机模拟浏览器操作
1. 在GitHub上可以下载到本专栏的专用项目源码只要把OpenResty解压到里面即可完成实验环境的搭建。
## 课下作业
1.按照今天所学的在你自己的电脑上搭建出这个HTTP实验环境并测试验证。
2.由于篇幅所限我无法详细介绍Wireshark你有时间可以再上网搜索Wireshark相关的资料了解更多的用法。
欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
<img src="https://static001.geekbang.org/resource/image/03/dd/03727c2a64cbc628ec18cf39a6a526dd.png" alt="unpreview">
<img src="https://static001.geekbang.org/resource/image/56/63/56d766fc04654a31536f554b8bde7b63.jpg" alt="unpreview">