从HTTP的发展史,彻底掌握HTTP——第一篇,从诞生到HTTP1.0的演进

前言

大家好,我是抹茶。之前我零星的获得HTTP的一些知识点,但是却串不起来。当我去系统梳理HTTP的发展史的时候,我才彻底弄懂它为什么设计成这样,解决了什么问题,有了自己的理解。希望这篇文章对你有同样的帮助。

先看看总体的脉络图,如下:

结合上图,可以概括出HTTP总共有三个大版本(论小版本就是5个),接下来就具体看看他们是如何进化的。

诞生:HTTP/ 0.9

HTTP/ 0.9是于1991年提出的,主要用于学术交流,目的是用来在网络之间传递HTML超文本的内容,所以被称为超文本传输协议(HTML的全称是HyperText Markup Language,直译为"超文本标记语言")。

HTTP/ 0.9的整体实现基于请求响应的模式,从客户端发出请求,服务器返回数据。

HTTP/ 0.9的请求流程

来看看一个HTTP/ 0.9的完整请求流程。

  • HTTP都是基于TCP协议的,客户端首先会根据IP地址、端口和服务器建立TCP连接(建立的过程就是TCP协议的三次握手)。
  • 建立好连接之后,会发送一个GET请求行消息,如GET /index.html用来获取index.html。
  • 服务器接收请求信息之后,读取对应的HTML文件,并将数据以ASCII字符流返回给客户端。
  • HTML文档传输完成后,断开连接。

HTTP/ 0.9的请求流程如下图:

总的来说,当时需要HTTP/ 0.9做的事情很简单,就是用来传输体积很小的HTML文件,所以它的实现有下面三个特点。

HTTP/ 0.9的特点

  1. 只有请求行。HTTP/ 0.9没有HTTP请求头和请求体,因为只用一个请求行就可以完整表达客户端的需求了。
  2. 服务端没有返回头消息。因为服务端并不需要告诉客户端太多信息,只需要返回数据就可以了。
  3. 返回的文件内容是以ASII字符流来传输的,因为都是HTML格式的文件,所以使用ASII字节码来传输是最合适的。

HTTP/1 : HTTP的性能优化

被浏览器推动的HTTP/ 1.0

HTTP/0.9虽然简单,但是已经可以满足当时需求。变化是世界永恒不变的主旋律。1994年出现了拨号上网,同年网景又推出了一款浏览器,从此万维网就不仅仅可以用在学术交流了,开始面向民用,迎来了高速发展阶段。随之而来的是万维网联盟(W3C)和HTTP工作组(HTTP-WG)的创建,它们致力于HTML的发展和HTTP的改进。

万维网的高速发展带来了很多的新需求,而HTTP/0.9已经不能满足新兴网络的需求,所以HTTP/0.9需要进化。

先来看看新兴网络带来了哪些新的需求。 首先在浏览器中展示的不单是HTML文件了,还包括了JavaScript、CSS、图片、音频、视频等不同类型的文件。因此支持多种类型的文件下载是HTTP/1.0的核心诉求,而且文件格式不仅仅局限于ASII编码,还有很多其他类型编码的文件。

所以如何能够支持多种文件类型的下载呢?

上面我们讲到客户端和服务器之间的通信语言是HTTP,不过HTTP/0.9在建立连接之后,只会发送类似GET/index.html这类的简单指令,而不能告知更多的信息,比如文件类型、编码等。同样,服务器也是直接返回数据给浏览器的,也没有其他方式告知更多的信息。

所以,我们需要引入新的设计,使得客户端和服务器之间可以交流更多的信息。

HTTP/ 1.0引入了请求头和响应头,它们都是以key-value形式保存的,在HTTP发送请求时,会带上请求头信息。服务器返回数据时,会先返回响应头信息。

HTTP/ 1.0具体的请求流程,如下图:

新增了请求头和响应头,浏览器和服务器就可以交流更多的信息了。那么浏览器是怎样通过请求头和响应头来支持多种不同类型的数据呢?

要支持多种类型的文件,需要解决以下的问题

  1. 浏览器如何知道服务器返回的是什么数据类型,因为可能是HTML、图片视频等等。
  2. 当万维网所支持的应用越来越广,单个文件的数据量也变得越来越大。为了减轻传输的性能,服务器会对数据进行压缩再传输,所以浏览器需要知道服务器压缩的方法
  3. 万维网是支持全球范围的,所以需要提供国际化的支持,服务器需要对不同的地区提供不同的语言版本,这就需要浏览器告诉服务器它想要什么语言版本的页面。
  4. 因为增加了不同类型的文件,而文件的编码方式可能不同,多样浏览器需要知道文件的编码类型

基于以上问题,HTTP/ 1.0的方案是通过请求头和响应头来协商,发起请求的时候,浏览器会通过请求头告知服务器期待返回的文件类型、支持的压缩方式、文件的语言以及具体的编码方式。最终发送的文件请求头内容如下:

js 复制代码
accept: text/html
accept-encoding: gzip, deflate, br
accept-Charset: ISO-8859-1,utf-8
accept-language: zh-CN,zh

第一行表示期待服务器返回html类型的文件。

第二行表示期待服务器可以采用gzip、deflate、br其中的一种压缩方式。

第三行表示期待返回的文件编码是ISO-8859-1或者utf-8。

第四行表示期望页面的优先语言是中文。

服务器接收到浏览器发送过来的请求头信息之后,会根据请求头的信息来准备响应数据。但是,如果浏览器请求的压缩类型是gzip,而服务器只支持br压缩,那么服务器就会通过相应头中的content-encoding字段来告诉浏览器最终的压缩类型,也就是说最终浏览器需要根据响应头的信息来处理数据,这个例子服务器的响应头数据信息如下:

js 复制代码
content-encoding: br
content-type: text/html; charset=UTF-8

第一行表示服务器采用了br的压缩方法。 第二行表示服务器返回的是html文件,并且该文件的编码类型是utf-8。

有了响应头的信息,浏览器会采用br来解压文件,再用utf-8的编码格式来处理原始文件,最后按照HTML的方式来解析该文件。这是HTTP/1.0支持多文件的一个基本的处理流程。

HTTP/ 1.0除了对文件有良好的支持之外,还依据当时的实际需求引入了其他特性,这些特性都是通过请求头和响应头来实现的。几个典型特性如下:

  1. 引入了状态码,以告知浏览器服务器最终处理该请求的情况。
  2. 提供了cache机制,可以缓存已经下载过的数据以减轻服务器的压力。
  3. 加入了用户代理(User-Agent)字段,使得服务器可以统计客户端的基础信息。

用户代理的信息如下图所示:

缝缝补补的HTTP/ 1.1

时代在发展,需求在变化。在新的业务场景中,发觉HTTP/1.0已经不能满足需求了,所以HTTP/ 1.1又在HTTP/ 1.0的基础上做了大量的更新。

接下来,我们来看HTTP/ 1.0遇到了哪些主要问题,以及HTTP/ 1.1是如何改进的。

1.改进持久连接

HTTP/ 1.0每进行一次HTTP通信,都需要经历TCP连接、传输HTTP数据和断开TCP连接这三个阶段,如下图

抛开剂量谈毒性是不道德的,在通信的文件内容小,每个页面需要发送请求不多的情况下,这样的设计没什么问题。但是随着浏览器的普及,单个页面中的图片文件越来越多,有的时候一个页面可能包含了几百个外部的引用,如果在去和服务器请求文件的时候,都要经历TCP连接、传输数据和断开连接这样的步骤,无疑会增加大量无谓的开销。

为了解决这个问题,HTTP/ 1.1中增加了持久连接,只有服务器或者浏览器没有明确断开连接,那么TCP连接会一直保持,实现了在一个TCP连接上传输多个HTTP请求。

如上图所示,HTTP的持久连接可以有效减少TCP连接和断开的次数,这样的好处是减少了服务器额外的负担,整体提升请求的速度。

持久连接在HTTP/1.1中是默认开启的。如果想要关闭,可以在HTTP头中加上Connection:close。目前浏览器中对于同一个域名,默认同时运行建立6个TCP长连接。

2.不成熟的管线化

持久连接虽然能够减少TCP的建立和断开次数,但是它需要等待前面的请求返回之后,才能进行下一次的请求。如果TCP通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面所有的请求,这就是著名的队头阻塞 问题。

HTTP/ 1.1尝试利用管线化的技术解决队头阻塞问题,主要表现为将多个HTTP请求整批提交给服务器,虽然可以批量发送请求,但是服务器依然需要根据请求顺序来回复浏览器的请求。

FireFox、Chrome都做过管线化的实验,但是由于各种原因,它们最终都放弃了管线化的技术。

3.提供对虚拟主机的支持

在HTTP/ 1.0中,一个域名对应一个IP地址,所以一个服务器只能支持一个域名。

随着虚拟主机技术的发展,需要实现在一台物理主机上绑定多个虚拟主机,每个虚拟主机都有自己的单独域名,这些域名共用同一个IP地址。

HTTP/ 1.1在请求头中加入了Host字段,用来表示当前的域名地址,这样服务器可以根据不同的host找到对应的虚拟主机。

4.支持动态生成内容(Chunk tranfer)机制

在设计HTTP/1.0时,需要在响应头中设置完整的数据大小,如Content-Length:601,这样浏览器就可以根据大小来接收数据。随着服务器端的技术发展,很多页面的内容都是动态生成的,因此在传输数据之前并不知道数据的最终大小,这就导致浏览器不知道什么时候是接收到了全部数据。

所以HTTP/1.1通过引入Chunk transfer机制来解决这个问题,服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的长度,最后用一个零长度的块作为数据完成的标志。这就实现了对动态内容的支持。

5.客户端Cookie、安全机制

客户端Cookie

随着互联网用户的增多,浏览器需要根据不同用户返回不同的内容,这就需要记录用户的登录状态。

在用户登录之后,服务器需要返回一个唯一的标识作为用户的身份证,浏览器将它记录下来,后续的请求中带上这个身份证,服务器就可以知道当前的请求来自哪个用户,从而确定返回什么信息。这个机制就是客户端Cookie。

如上图,一般登录需要输入用户名的密码,这些信息发送到服务器后,服务器校验通过,会生成一段表示用户身份的字符串作为用户的身份证,并将该字符串写到响应头的Set-Cookie字段中。

浏览器在接收到服务器的响应头后,开始解析响应头,如果响应头中含有Set-Cookie字段,浏览器会把这个字段信息保存到本地。

如图,掘金在登录之后就会在客户端的Cookie加一堆东西。

在后续的请求中,客户端会自动在请求中加入Cookie值再发送出去。服务器端发现客户端发送过来的Cookie值后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到用户的状态信息。如下图,掘金会在请求中加入Cookie字段。

安全机制

HTTP是明文传输的,所以传输过程的每一个环节都有可能被篡改信息。所以需要引入安全机制保障传输数据的安全性。 这块内容很多,本文篇幅已经很长了,后面单独写篇文章。

总结

通过HTTP/ 0.9、HTTP/ 1.0、HTTP/ 1.1我们可以看到HTTP的进化史是随着浏览器的发展、互联网用户的增加而不断演变的,每一次改动都是为了解决当下的卡点,更好的应对业务场景。总的内容有下面几点

  • HTTP/ 0.9,HTTP的鼻祖,一开始主要用于学术交流,传输的内容比较简单,用ASII字符流就能应对,只有请求行和响应行。
  • HTTP/ 1.0,随着网景浏览器的发展壮大,需要传输的内容越来越多,类型也是更加丰富,为了支持多种文件类型,引入了请求头和响应头。
  • HTTP/ 1.1,随着网页引入的内容变多,请求也变多,每次请求都经历TCP连接、传输数据、断开连接的方式很影响速度,所以支持了TCP长连接。

每一次改进都是为了更好应对当下,篇幅已经很长了,后面会接着写HTTP/ 2.0和HTTP/ 3.0以及安全机制(HTTPS),应该每个会单独一篇文章。

相关推荐
正小安20 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
GZ_TOGOGO2 小时前
【2024最新】华为HCIE认证考试流程
大数据·人工智能·网络协议·网络安全·华为
三金121383 小时前
SpringIoC容器的初识
网络·网络协议·rpc
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器