所谓应用层,便是指生活中一些基础的应用所处的层次,也就是我们日常所能够看到的,诸如 Web 网页,电子邮件等这些基础的应用所使用的协议。

本篇内容,主要说说最为重要、最为基础的 HTTP 协议。

HTTP协议

我们所浏览的 Web 网页,其主要是基于 HTTP 协议所搭建的。

HTTP 协议,英文全称为 Hyper Text Transfer Protocol (超文本传输协议),其是一种双端协议,也就是说,这个协议是有两个版本的,一个是服务端的协议一个是客户端的协议。

正如 Computer Networking, A Top-Down Approach 中所说的那样:HTTP defines how Web clients request Web pages from Web servers and how servers transfer Web pages to clients. HTTP 定义了 Web 客户端如何从 Web 服务器请求网页以及 Web 服务器如何向 Web 客户端传输结果。

HTTP报文格式

HTTP 规范包含了对HTTP报文格式的定义,正如上述所说,由于服务端与客户端的不同,共有两种报文。

HTTP 请求报文

下面是一个典型的HTTP请求报文,来自我请求百度主页时候的报文复制(并未按顺序全部复制):

1
2
3
4
5
6
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

首先可知,报文时使用 ASCII 编码书写的;然后,可以按照规定,将请求报文分为三个部分:请求行(Request Line),请求头(Header Lines),请求体(Entity body)。

以上面的例子来说明上述几个部分:

  • 第一行也就是请求行,其对应关系为:

    1
    2
    GET / HTTP/1.1
    请求方法 请求路径 请求协议/协议版本

  • 然后便是请求头,其由冒号后加一空格将头和值隔开

    1
    2
    3
    Host: www.baidu.com
    Connection: keep-alive
    ...
  • 随着一个空行,之后的内容便是请求体,使用 GET 方法时,并没有请求体,所以上面的请求报文中并没有请求体。

综上所述,其格式如下图所示:

请求报文格式
请求报文格式
  • 其中,sp 为空格,cr 为回车,lf 为换行。

HTTP响应报文

既然有请求,那就会有响应,下面是一个典型的HTTP响应报文,也是来自我请求百度主页时候的报文复制(并未按顺序全部复制):

1
2
3
4
5
6
7
HTTP/1.1 200 OK
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Fri, 01 May 2020 09:32:25 GMT
Expires: Fri, 01 May 2020 09:32:25 GMT
Server: BWS/1.1

同样,也可以按照规定,将响应报文分为三个部分:响应行(Status Line),响应头(Header Lines),响应体(Entity body)。

  • 第一行为响应行,其对应关系为:

    1
    2
    HTTP/1.1 200 OK
    协议名/协议版本 状态码 描述状态码的短语
  • 之后的各行为响应头:

    1
    2
    3
    Connection: keep-alive
    Content-Encoding: gzip
    ...
  • 同样随着一个空行,之后的内容便是响应体,响应来的一般是一个 HTML 文件。

综上所述,其格式如下图所示:

响应报文格式.jpg
响应报文格式.jpg

Cookies

由于 HTTP 服务是无状态的,但是日常中,Web 站点更希望能识别用户,提供个性化服务或者限制用户的访问,为了达到这个目的,HTTP 使用了cookie 。

Cookie 有四个重要的组件:

  • HTTP 响应报文有一个 cookie 首部行
  • HTTP 请求报文有一个 cookie 首部行
  • 用户端系统保存有一个 cookie 文件
  • Web 站点有一个后端数据库

首次访问

  • 首次使用浏览器访问某个 Web 网站,Web 站点产生一个唯一的识别码,以该索引码作为索引在后端数据库中产生一个新的表项。然后在响应报文中加入 Set-cookie 的头部,比如:

    1
    Set-cookie: 1678
  • 浏览器收到了 HTTP 响应报文,识别 Set-cookie 之后,会在其管理的 cookie 文件中添加一行(包括服务器的主机名和 Set-cookie 中的识别码)。

此时,初次添加 cookie 便完成了,那么之后,你在该网站的一举一动都会被记录,无论是你浏览了什么还是点击了什么。

再次访问

几天之后,你又一次访问该网站。

  • 浏览器会在 cookie 文件中检测是否有该网站的 cookie ;如果有,便会将保存的 cookie 作为请求报文的头发给服务端,比如:

    1
    cookie: 1678
  • 服务端根据你的 cookie 读取你的信息,并根据此值查询数据库的信息,给你推荐相关产品或者广告。

cookie 的本意是简化一些操作,但是经常被滥用,借此收集用户的信息,甚至收集后将信息卖给第三方,实实在在地侵害了用户的隐私。

Web 缓存

缓存服务器或者代理服务器,其实很容易理解,就是一个服务器与客户端之间的中转。而这部分的重心,我觉得是实实在在理解缓存带来的优势。

缓存演示

有这样一个简单的网络模型1

简单网络结构.jpg
简单网络结构.jpg

假设,机构网络(Institutional network)中一个请求从发出到接收到共需要 2 秒,可将其非正式地称之为 “Internet delay”(因特网时延);假设现在每秒发送 15 个请求,每个请求平均长度为 1Mbits 。

  • 首先估算机构局域网中的流量强度:\((15 请求/秒)⋅\frac{1 Mb/请求}{100 Mbps} =0.15\)
  • 然后估算接入链路上的流量强度:\((15 请求/秒)⋅\frac{1 Mb/请求}{15 Mbps} = 1\)

链路上流量强度达到了 1 ,网络时延会变得无限大,这显然是不行的。

于是使用一个 Web 缓存,将网络结构变为下图这种方式:

加入缓存的网络结构.jpg
加入缓存的网络结构.jpg

和上面的假设一样,除此之外,假设命中率(一个缓存器所满足的请求的比率)为 0.4 。那么便会有 40% 的请求由缓存服务器处理,60% 的缓存由初始服务器满足。

由于原来的 100% 变为了现在的 60% ,流量强度也由 1.0 变为 0.6 ,一般来说,流量强度小于 0.8 的时候,时延约为几十毫秒。此时需要花费的时间为:

\[ 0.4 \times (0.010)秒 \ + \ 0.6 \times (2.01秒) = 1.21秒 \]

效果可见一斑了。

更新缓存

缓存是会过期的,因为目标服务器不可能总时一成不变的,一旦服务器发生了更新,那么缓存还维持原来的内容便有点说不过去了。

更新缓存所使用的是 条件GET方法 ,条件 GET 为了减少传输的数据量,只发送一个包含简单几个头的GET请求,来询问服务器数据是否发生了改变,一般如下所示:

1
2
3
GET /fruit/kiwi.gif HTTP/1.1
Host: www.exotiquecuisine.com
If-modified-since: Wed, 9 Sep 2015 09:23:24

其中 If-modified-since 头的日期数据,就是缓存服务器中数据的更新日期,如果并未发生改变,服务器会发送一个空的响应,并设置状态码为 304 ,并不会像普通的GET的响应一样,会发送网页或者请求的数据。

1
2
3
4
5
HTTP/1.1 304 Not Modified
Date: Sat, 10 Oct 2015 15:39:29
Server: Apache/1.3.0 (Unix)

(empty entity body)

HTTP版本

现行的 HTTP 协议经历了几个重要的版本更迭,分别是 1.01.1 以及最新的 2.0

HTTP 1.0 是最为基础的版本,所以拥有最基本的 HTTP 功能,其至今仍被广泛采用,关于 HTTP 1.0 的相关内容,并不需要过于长篇大论的介绍。

HTTP 1.1 是在 1.0 之后推出的一个版本,也是如今最为应用广泛的版本,所以重心应该集中在 1.11.0 的改进。在 1.1 中,引进了Persistent Connections等新特性,做出了重要改进。

Persistent Connections

Persistent Connections(持久性连接)是在 1.1 之后加入的新特性。

1.0 的时候,一次连接只能发送和接收一次请求,也就是说,假如有一个网页,网页上有 10 张图片,那么这时候,便需要进行 11 次 TCP 连接,每个文件传输完毕之后都会关闭 TCP 连接,这就造成了极大的时间浪费。并且每个请求代对象都需要建立和维护一个全新的连接,在客户端和服务器中分配 TCP 缓冲区和保持 TCP 变量,这也会给 Web 服务器带来严重的负担。

1.1 之后,默认都是长连接,也就是在处理事务结束之后也不会将 TCP 连接关闭,而是继续保持以便复用,这就节省了很大一部分不必要的时间。

其实 1.0 中,添加请求头 Connection: Keep-Alive 也能够达到长连接的效果,但是随着互联网的发展,网页内容逐渐丰富,并不像 1.0 时代那样只有一个网页和几张图片了,所以干脆在 1.1 之后直接默认为持久性连接了。

其实 1.1 还加入了不少新特性,只是我没有深入了解,就不再赘述了

HTTP 2.0

HTTP 2.0 ,既然大版本号发生了更迭,那么就意味着 2.0 是下一代 HTTP 协议。当然,这个版本目前应用还非常少。

2.0 版本最大的特点是加入了多路复用技术,在不改动原语义、方法等核心概念的基础上,增加了二进制分帧层HTTP 2.0 会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码 ,其中 HTTP1.x 的首部信息会被封装到 Headers 帧,而我们的 request body 则封装到 Data 帧里2

HTTPS

HTTP 协议在传送消息时,是明文发送的,如果有人截取传送的消息,那么你的一切将会暴露在他面前,包括你的信用卡号甚至密码。

网景公司于 1994 年首次提出,将HTTP的数据包利用 SSL/TLS 进行加密,从而提供对网站服务器的身份认证,以及保证资料交换的隐私性与完整性,后来才扩展到整个互联网上3

HTTP 与 HTTPS4

  • HTTP 默认使用 80 端口;HTTPS 默认使用 443 端口。
  • 严格来说 HTTPS 并不是一个单独的协议,而是对工作在加密连接(TLS或SSL)上的常规 HTTP 协议的称呼。
  • 要使一网络服务器准备好接受HTTPS连接,管理员必须创建一数字证书,并交由证书颁发机构签名以使浏览器接受。证书颁发机构会验证数字证书持有人和其声明的为同一人

参考链接


  1. 文中所有的图片都来源于教材 Computer Networking, A Top-Down Approach 英文版。

  2. 似水流年的知乎文章:HTTP协议几个版本的比较

  3. 维基百科:超文本传输协议

  4. 维基百科:超文本传输协议