HTTP 必知必会

901 阅读15分钟

Web 是我们程序员非常熟悉的一种应用, HTTP 是支持 web 应用的协议,但是你真的了解他们吗?今天我们来跟着大师的脚步,从计算机网络的角度看 Web 和 HTTP 协议,相信你会有新的收获。✌️

前情提要

系统地学习计算机基础知识,并用博客记录下来。我们的教材是 《计算机网络-自顶向下方法(第7版)》,中科大郑烇、杨坚全套《计算机网络》

计算机网络:Internet基本原理(上)

计算机网络:Internet基本原理(下)

计算机网络:应用层协议原理

这篇是第二章应用层之 Web 和 HTTP,参考资料是图解 HTTP

一些术语

  • Web页:由一些对象组成

    • 什么叫对象?对象可以是HTML文件、JPEG图像、Java小程序、声音剪辑文件等等,万物皆对象。
    • Web 网页含有基本的 HTML 文件,该基本 HTML 文件又包含若干对象的引用链接。

  • 通过 URL 对每个对象进行引用

    • 任何对象,都可以采用 URL 的方式来访问。比如在网页中嵌入的图片,我们不是直接把图片嵌入网页中,而且使用图片的对象的链接来引入它。

  • URL 的格式:访问协议,用户名,口令字,主机名,路径名,端口等等。熟悉 web 的同学可能会有疑问,怎么和我们平常见到的不一样呀?没关系,我们来逐一分解。

    • 协议:告诉我们采用什么协议来访问对象,比如 HTTP、FTP、email 等等,后面必须要加 ://
    • 用户名口令:我们在访问对象的时候,采用什么样的用户名和口令去访问它。当然用户名口令是经常省略的,因为它并不安全不推荐使用。
    • 主机名、路径名:对象在主机的域名下的路径的名称,还有对象的文件类型。
    • 端口:计算机与外界通讯交流的出口。HTTP 默认端口是 80,HTTPS 是 443。

互联网当中的所有的对象都是采用这种方式来指向的。所以说,互联网的 web 对象,就像一个蜘蛛网一样,采用网状的结构,指向其他信息。

到目前为止,互联网当中的网页的数量还是非常惊人的,是非常复杂的信息空间。如果我们想在蜘蛛网里找东西,是不是很困难呢?

所以就有了搜索引擎。你向搜索引擎提供关键字,它把匹配的内容返回给你。把热度、关联度比较高的对象,推在前面。当然了,web 应用是互联网杀手级的应用,它吸引了大量的用户,包括企业用户、个人用户。他们把信息挂在网上,只要下载浏览器客户端,就可以访问世界上任何网站。

HTTP 扫盲

HTTP:超文本传输协议

  • Web的应用层协议

  • 客户/服务器模式

    • 客户:请求、接收和显示
    • Web对象的浏览器 服务器:对请求进行响应, 发送对象的Web服务器

我们来看一下支持 web 应用的 HTTP 协议,超文本传输协议。

  • 超文本:指的是文本与文本之间任意的指向关系。web对象不就是这样吗?一个 web 对象包括了很多链接,链接又指向其他的对象,还可能反指回来。通过这种关系,构成了巨大的复杂的网状的信息空间。
  • 协议:浏览器和服务器之间通讯需要遵守的规范。首先建立起 TCP 的连接,在连接之上发送 HTTP 的请求。web 服务器收到请求之后,把客户端请求的对象封装成 HTTP 的响应报文,返回给浏览器。不管是 PC 端还是移动终端,都是采用这种方式来工作的。

使用 TCP

那么具体是怎么工作的呢?

  • 首先服务器要运转在某个固定 IP 的 80 端口上,等待客户端的 TCP 连接建立请求。

  • 服务器接受客户的 TCP 连接

    • 客户端请求建立连接之后,服务器才会同意连接建立请求。之后 web 服务器就有了 socket 指向他们的会话关系。(不明白 socket 的可以去看上一篇 计算机网络:应用层协议原理
  • 在浏览器(HTTP客户端)与Web服务器(HTTP服 务器server)交换HTTP 报文(应用层协议报文)

    • 连接建立完了之后呢, web 浏览器就可以采用 HTTP 的协议向服务器发送 HTTP 的请求。
    • 服务器响应请求,把 HTTP 请求的对象封装成响应报文,发送回来。
    • web 浏览器拿到被请求的对象之后,再做相应的处理。
  • 最后 TCP 连接关闭

HTTP 是无状态的

HTTP 的协议在一开始设计的时候,就是无状态的。也就是说,服务器不维护任何关于客户的信息。

服务器只负责连接建立、返回请求报文,并不知道你的客户端以前有没有和他通讯过,也不知道以后你们会不会再次通讯。

那为什么要这样设计呢?或者说,这样设计有什么好处呢?

维护状态的协议很复杂。

  • 如果服务器必须维护一些历史信息(状态) 。某一天客户端跟它建立连接之后死机了,它们的状态信息很可能是不一致的。

    • 这个时候,服务器还要设定一些的机制,让双方重新回到同步的状态。
  • 无状态的服务器能够支持更多的客户端。

    • 同样的网络,同样的服务器资源,无状态的服务器可以支持用户的数量可能远超于用状态的服务器。因为服务器不需要维护浏览器的状态了,资源得到了释放。

HTTP 非持久 VS. 持久

我们来看一下非持久和持久。分别对应 HTTP 1.0 和 1.1 的两个版本。

HTTP 1.0 :非持久连接。

HTTP协议的初始版本 1.0 中,每进行一次HTTP通信就要断开一次TCP连接。也就是说,最多只有一个对象在TCP连接上发送,下载多个对象需要多个TCP连接。

在互联网早期,这种协议是可以正常运行的,因为传输的都是些容量很小的文本。但在现在网站动辄几十条HTTP请求的情况下,很容易达到浏览器请求上限,并且每次请求都建立新的tcp连接(每次都有三次握手四次挥别)极大的增加了通信开销。

所以在 HTTP/1.1 中默认使用持久连接(HTTP Persistent Connections,也称为 HTTP keep-alive 或 HTTP connection reuse)。也就是说,多个对象可以在一个客户端和服务器之间的 TCP 连接上传输。只要两端都没有提出断开连接,则持久保持TCP连接状态,其他请求可以复用这个连接通道。

非持久 HTTP 连接

当用户输入 URL 访问页面,这个页面里包括文本和10个 jpeg 图像的引用时,会发生什么事情。👇

响应时间模型

图中的 RTT( round-trip time)是数据流往返的网络耗时,一个小的分组从客户端到服务器,再回到客户 端的时间,其中传输时间忽略。

那为什么传输时间忽略不计呢。因为是小的分组,相对于它的带宽来说的,字节数很少,所以需要传输时间很少。

在非持久性的 http 连接当中,一个对象的响应时间等于2RTT+传输时间。一个RTT用来发起TCP连接,另一个一个RTT用来HTTP请求并等待HTTP响应,还要加上文件传输时间。

从这里我们可以看出,非持久连接需要花费很长的时间,所以说就诞生了持久连接。

持久 HTTP

而持久又分两种,一种叫流水线 pipeline , 另外一种叫 non pipeline 非流水线。

管线化 / 流水线

非流水线

一次只有一个请求,只有在前面对象回来之后,才能发出另外对象的请求。 比如说,浏览器请求 10 个图片,先请求第一个图片,只有第一个图片回来了,才能请求第二个;第二个对象回来,再请求三个对象……

流水线

另外一种方式叫流水线方式。一次有十个对象要请求,第一个对象请求发出去,还没回来的时候,我就接着发出第二个、第三个一直到第十个。我们把这种请求的方式,称之为流水方式。

就像生产汽车,非流水线方式是同一时刻,只生产一辆汽车,而流水线可能同时有1万辆车在生产。

再回到持久连接,它让多个数请求以流水线(pipelining)方式发送成为可能。也就是说,以前发送请求后需等待并收到响应,才能发送下一个请求。而现在,使用管线化技术,不用等待响应就可直接发送下一个请求。

流水方式是 http1.1 版本的默认方式,每个对象花费有可能只花费一个 rtt。

HTTP 报文

用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文叫做请求报文,响应端(服务器端)的叫做响应报文。

通用格式

请求报文

响应报文

请求报文和响应报文的首部内容由以下数据组成。

  • 请求行:包含用于请求的方法,请求URI和HTTP版本
  • 状态行:包含表明响应结果的状态码,原因短语和HTTP版本
  • 首部字段:包含表示请求和响应的各种条件和属性的各类首部

方法类型

HTTP 1.0

  • GET:获取资源
  • POST:传输实体主体
  • HEAD:获取报文首部,不返回报文主体

HTTP 1.1 增加

  • PUT:传输文件
  • DELETE:删除文件
  • OPTIONS:用于询问请求 URI 资源支持的方法

状态码

推荐状态码学习网站:http.cat/

100

  • 1** 信息,服务器收到请求,需要请求者继续执行操作

200

  • 2** 成功,操作被成功接收并处理

    • 205 No Content。请求处理成功,但没有资源可返回。
  • 206 Partial Content。该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET请求。响应报文中包含由 Content- Range 指定范围的实体内容

300

  • 3** 重定向,需要进一步的操作以完成请求

    • 301 Moved Permanently 永久性重定向。该状态码表示请求的资源已被分配了新的URL,以后

应使用资源现在所指的 URL

  • 302 Found 临时性重定向。
  • 304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源

400

  • 4** 客户端错误,请求包含语法错误或无法完成请求

    • 400 Bad Request 客户端请求的语法错误,服务器无法理解
  • 401 Unauthorized 请求要求用户的身份认证
  • 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
  • 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
  • 405 Method Not Allowed 客户端请求中的方法被禁止

500

  • 5** 服务器错误,服务器在处理请求的过程中发生了错误

    • 502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
  • 504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求

Web 缓存 —— 代理服务器

那么我们来看另外一个主题,就是 web 的 cache 缓存。

什么是 Web 缓存?

缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。

也就是说,我们有两种访问服务器的方式。

  • 第一种:直接访问 web 服务器,直接从源服务器获取对象。
  • 另一种:设置 web 代理服务器,通过代理获取对象。

Via: 代理服务器相关信息,每经过一个代理服务器就会添加相关信息,用逗号分割

如果代理服务器没有对象,他就向原始的服务器请求对象,同时在它的代理服务器的文件系统中将这个对象缓存下来。

下次如果有其他的用户再访问同样的对象,代理服务器就直接从本地文件系统当中把它读取出来,形成 response 报文反转给用户。我们把这个行为叫做对象在代理中被命中了。

为什么要使用 Web 缓存?

一个字,快。

  • 对用户来说,降低客户端的请求响应时间
  • 对 ISP (互联网服务提供商 Internet Service Provider,比如移动。)来说,可以大大减少一个机构内部网络与 Internent 接入链路上的流量
  • 对 ICP (网络内容服务商,全称 Internet Content Provider,比如谷歌)来说,互联网大量采用了缓存:可以使较弱的 ICP 也能够有效提供内容

而且,互联网的内容访问遵守二八分布原则,也就是说 80% 的人访问 20% 的内容。

那么,我们只用安排非常小的缓存,就可以命中很多用户的访问请求,从而减少服务器、网络的负担。

所以说,缓存对客户端来说,它是服务器,而对原始服务器而言,它是客户端。通常缓存是由 ISP 安装的,比如大学、公司、居民区 ISP。

代理服务器把访问的对象缓存下来,直接返回给用户。这种缓存的方法有没有什么漏洞呢?

当然是有的,如果原始服务器的对象有变化,代理服务器返回给用户的,就是错误的对象。所以,HTTP 协议也有了相应的处理措施。

条件 GET 方法

那么 http 协议也做了升级,conditional get 条件时获取。升级的目标是,如果缓存器中的对象拷贝是最新的,原始服务器就不会发送对象。

HTTP 缓存有哪几种?

具体有这些条件,我们来一一分析。

HTTP 1.0

为了减轻服务器的压力,在 HTTP/1.0 中提供了 Cache 机制。

  • Expires:强制缓存。缓存服务器上的过期时间。

    • 用来指定资源到期的时间
  • 问题:受限于本地时间。如果用户改了本地时间,就没用了
  • Last-Modified:协商缓存。

    • 资源在服务器上的最后修改时间。
  • 问题:一个资源被修改了,但其实际内容根本没发生改变,也会返回整个实体给客户端(即使客户端缓存里有个一模一样的资源)。

客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码,内容为空,这样就节省了传输数据量 。如果两个时间不一致,则服务器会返回该资源并返回200状态码,和第一次请求时类似。这样保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。一个304响应比一个静态资源通常小得多,这样就节省了网络带宽。

HTTP/1.1

随着技术的发展,很快 HTTP/1.0 也不能满足需求了。

  • Cache-Control: 强制缓存

    • Expires http1.1 新增了 Cache-Control 来定义缓存过期时间 max-age=3600

注意:若报文中同时出现了 ExpiresCache-Control,则以 Cache-Control 为准。

  • ETag:协商缓存:根据内容计算出的唯一标识符

    • 为了解决上述 Last-Modified 可能存在的不准确的问题,Http1.1 还推出了 ETag 实体首部字段。

强制缓存 与 协商缓存

  1. 浏览器在加载资源时,根据请求头的 expirescache-control 判断是否命中强缓存,是则直接从缓存读取资源,不会发请求到服务器。
  2. 如果没有命中强缓存,浏览器一定会发送一个请求到服务器,通过 last-modifiedetag 验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的数据,依然是从缓存中读取资源
  3. 如果前面两者都没有命中,直接从服务器加载资源