HTTP: 超文本传输协议(英文:HyperText Transfer Protocol, 缩写:HTTP)是一种用于分布式、
协作式和超媒体信息系统的应用层协议。HTTP 是万维网的数据通信的基础
相信作为一个程序员,对于 HTTP 这个词并不陌生,甚至还每天都会打交道。但是如果在 HTTP 后面加几个数字,那么你们又是否能分得清呢? 可能很多人很眼熟,但是要他细说其中的一二,可能这时又会“混乱”起来了,那么今天,我们就来好好整理一番。
1、前提
在说 HTTP 之前,先来简单说一下五层协议、三次握手还有带宽与延迟。
1.1、五层协议
如上图所示:
- 物理层主要作用是定义物理设备如何传输数据「 网卡端口、网线、光缆 」
- 数据链路层在通信的实体间建立数据链路连接
- 网络层为数据在节点直接传输创建逻辑链路「 IP协议 」
- 传输层向用户提供可靠的端到端服务 「 TCP协议 」
- 应用层为应用软件提供许多服务,构建于TCP协议之上 「 HTTP协议 」
1.2、三次握手
如上图所示:
- 第一次握手:客户端发送 syn 标志位和 seqNum,向服务器申请建立连接,客户端状态由 closed 变为 syn_send, 并等待服务器确认
- 第二次握手:服务端返回 syn 和 ack 标志位,ackNum 以及 seqNum,确认第一次握手的报文段,返回 ackNum = seqNum(第一次握手发送的)+1,同意建立连接,服务器状态由 listen 变为 syn_received。
- 第三次握手:客户端发送确认报文段,返回 ack 以及 ackNum = seqNum(第二次握手发送的)+1,客户端状态变为:established (完成连接)
- 最后,服务器收到确认报文段,服务器状态由 syn_received 变为 established (完成连接)
为什么一定要三次握手呢? 两次或者四次可以么?
1.3、带宽与延迟
影响 HTTP 请求的原因有两个:带宽与延迟
带宽:如今互联网时代,带宽已经不是一个需要我们去担心的问题,5G 时代的来临更是把这个问题给切底解决了,所以我们需要看的是延迟。
延迟:
- 浏览器阻塞 (head of line blocking):浏览器会因为一些原因阻塞请求。浏览器对于同一个域名,同时只能有 4 个连接(浏览器内核不同可能会有所差异),超过浏览器最大连接数限制,后续请求就会被阻塞。
- 连接无法复用:HTTP 是基于 TCP 协议的,导致每次请求经历3次握手和慢启动。3次握手在高延迟的场景下影响较为明显,慢启动则对文件类大请求影响较大
- DNS 查询(DNS Lookup):浏览器需要知道目标服务器的 IP 才能建立连接。将域名解析为 IP 的这个系统就是 DNS。这个通常可以利用DNS缓存结果来达到减少这个时间的目的。如果想了解更多 DNS 查询的知识,可点击 DNS查询
2、HTTP 的历史
由下图所示:
HTTP/0.9
1990年问世,那时的 HTTP 并没有作为正式的标准被建立,这时的 HTTP 其实含有 HTTP/1.0 之前版本的意思,那时候还有严重设计缺陷,只支持 GET 方法,不支持 MIM 类型,很快被 HTTP/1.0 取代。
并且协议还规定,服务器只能回应 HTML 格式的字符串,不能回应别的格式,当服务器发送完毕,就关闭 TCP 连接。
GET /index.html //请求 index.html
Hello World
HTTP/1.0
HTTP正式作为标准被公布是在1996年的5月,版本被命名为 HTTP/1.0,并记载于RFC1945。虽然说是初期标准,但该协议标准至今仍被使用在服务器端。
HTTP/1.0 相对起 HTTP/0.9,不仅可以传输文字,还可以传输图像、视频、二进制文件等。并且多了 POST 和 HEAD 命令。
HTTP 请求回应的格式也有所变化,除了数据部分,每次通信都必须包括头信息。还新增了状态码、缓存、内容编码等等。
请求:
GET / HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
服务器响应:
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
Hello World
缺点:每次 TCP 连接只能发送一个请求,发送数据完毕,连接就关闭。如果需要请求其他的资源,需要再建一个连接。(新建一个 TCP 连接的成本很大)
为了解决这个问题,有的浏览器在请求的时候加上一个 Connection 字段。
Connection: keep-alive
HTTP/1.1
1997年公布的 HTTP/1.1 是目前主流的 HTTP 协议版本。之前的标准是RFC2068,之后又发布了修订版RFC2616。
HTTP/1.1 针对 HTTP/1.0,进行了以下的改进点:
- 持久连接:HTTP/1.1 渐渐暂停了对 keep-alive 连接的支持,用一种名为持久连接(persistent-connection)的改进设计取代了它。与 keep-alive 不同,HTTP/1.1 中 persistent 连接默认就是激活的,除非特别指明,否则 HTTP/1.1 认为所有连接都是持久的。HTTP/1.1的客户端假定在收到的响应后,除非报文包含了 Connection: Close 首部,否则客户端就认为连接仍为维持在打开状态。
目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。
- 管道机制(pipelining):即在同一个 TCP 连接里面,客户端可以同时发送多个请求。这样就进一步改进了 HTTP 协议的效率。
举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求。管道机制则是允许浏览器同时发出 A 请求和 B 请求,但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求。 - content-Length:声明本次回应的数据长度。
Content-Length: 2485
上面的代码告诉浏览器,本次回应的长度是 2485 个字节,后面的字节就属于下一个回应了。
- 分块传输编码:使用 Content-Length 字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。对于很耗时的操作来说效率不高。于是有了更好的处理方式:产生一块数据,就发送一块。
因此,HTTP/1.1 规定可以不使用 Content-Length 字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有 Transfer-Encoding 字段,就表明回应将由数量未定的数据块组成。
Transfer-Encoding: chunked
- 新增请求方式:HTTP/1.1 新增了许多请求方式:
PUT
、PATCH
、OPTIONS
、DELETE
、HEAD
HTTP/2
2015年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3
HTTP/2 的出现,大大的优化了服务端与客户端之间的连接。
HTTP/2 是基于 HTTPS 的,如果需要使用HTTP/2,必须启用HTTPS,针对 HTTPS的内容,这里
性能惊人:
可以看看以下的例子,是 Akamai 公司建立的一个官方的演示,用 HTTP/1.1 和 HTTP/2 同时请求 379 张图片,从Load time 的对比可以看出 HTTP/2 在速度上的优势。
点击体验地址
性能惊人的原因:
- 二进制分帧
HTTP1.x 的解析是基于文本(ASCLL 编码)。数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制。并且统称为“帧”(frame):头信息帧和数据帧。
二进制协议的好处:可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。
- 多路复用(双工通信)
通过单一的 HTTP/2 连接发起多重的请求-响应消息,即在一个连接里,客户端和浏览器都可以同时发送多个请求和响应,而不用按照顺序一一对应,这样避免了“队头堵塞”。
- 数据流
HTTP/2 的数据包是不按顺序发送的,同一个连接里面的数据包,可能属于不同的回应。因此 HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号,数据包发送的时候,都会标记数据流ID,用来区分属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。HTTP/1.1 取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
- 首部压缩
HTTP/1.x 的 header 带有大量信息,而且每次都要重新发送,HTTP/2 使用 encoder 来减少需要传输的 header 大小,通讯双方各自缓存一份 header dields 表,这样既可以避免重复 header 的传输,又减少了需要传输的大小。
- 服务端推送
服务端推送是指:用服务端主动发起连接,推送信息给客户端。
在 HTTP /2 之前,如果要实现服务端推送,有以下几种方式:
- 传统轮询:定时向服务端请求刷新,这样的方式非常浪费资源,给服务器造成比较大的负担。
- 长轮询:每次客户端发出请求后,服务器检查上次返回的数据与此次请求时的数据之间是否有更新,如果有更新则返回新的数据并结束此次连接,否则服务端就“hold”住此次连接,直到有新数据再返回。这种做法也是非常消耗服务器资源的。
- WebSocket:客户端向 WebSocket 服务器通知(notify)一个带有所有接收者 ID 的事件(event),服务器接收后立即通知所有活跃的(active)客户端,只有 ID 在接收者 ID 序列中的客户端才会处理这个事件。这种实现方式无需重复发请求头部,节省带宽,对浏览器支持也很好,但是需要 Socket 程序实现和额外端口。
HTTP/2 允许服务器未经请求,主动向客户端发送资源。常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
参考:
「HTTPS」-- 你所必须了解的东西
HTTP 协议入门
HTTP1.0、HTTP1.1 和 HTTP2.0 的区别
详解HTTP/1.0、HTTP/1.1、HTTP/2、HTTPS