什么是HTTP

HTTP全称超文本传输协议(HyperText Transfer Protocol),诞生于 1989年3月,由 CERN(欧洲核子研究组织)的 Tim Berners Lee 博士和他的团队设计,是一种能够获取如 HTML 这样的网络资源的通讯协议。它是在 Web 上进行数据交换的基础,是一种 客户端-服务器 协议,也就是说,请求通常是由像浏览器这样的客户端发起的。一个完整的Web文档通常是由不同的子文档拼接而成的,像是文本、布局描述、图片、视频、脚本等等。

HTTP正式作为标准是在 1996年的5月,版本被命名为 HTTP/1.0,并记载于 RFC1945

HTTP在基本的TCP/IP协议栈上发送信息,1994年底,网景公司(Netscape Communication)在此基础上创建了一个额外的加密传输层:SSL(Secure Socket Layer 安全套接层),SSL在标准化道路上最终成为TLS(Transport Layer Security 安全传输层协议),并记载于 RFC2246

1997年1月 HTTP/1.1公布,当初的标准是 RFC2068,目前最新的修订版是1999年6月发布的 RFC2616

HTTP2目前正在设计中,它的两个预览版本 RFC7230RFC7235 发布于2014年6月

计算机网络模型

HTTP 是被用来进行计算机通信的一个应用层协议,它的运行基础是计算机网络。被广为人知的计算机网络模型一般有两种,一个是被ISO(International Organization for Standardization 国际标准化组织)制定的 OSI(Open System Interconnection)七层模型(包括应用层、表示层、会话层、传输层、网络层、数据链路层、物理层,实际使用中该模型太过理想化,并没有被广泛的采用),另一个是被实际使用的 TCP/IP 模型。TCP/IP 模型按通信层次分为以下五层:应用层、传输层、网络层、数据链路层、物理层(一般把数据链路层与物理层统称为网络接口层)。

应用层

应用层决定了向用户提供应用服务时通信的活动。
属于该层的协议有 FTP(File Transfer Protocol 文件传输协议)、 SMTP(Simple Mail Transfer Protocol 简单邮件传送协议)、 DNS(Domain Name System 域名系统)、 HTTP(HyperText Transfer Protocol 超文本传输协议)、Telnet(远程登录协议) 、POP3(Post Office Protocol - Version 3 邮局协议版本3)、 SNMP(Simple Network Management Protocol 简单网络管理协议)、DHCP(Dynamic Host Configuration Protocol 动态主机配置协议)、SSH(Secure SHell protocol 安全外壳协议)

传输层

传输层提供处于网络连接中的两台计算机之间的数据传输。
属于该层的协议有 TCP(Transmission Control Protocol 传输控制协议) UDP(User Data Protocol 用户数据报协议)

网络层

网络层用来处理在网络上流动的数据包。
属于该层的协议有 IP(Internet Protocol 网络互联协议)包括 IPv4、Ipv6, ICMP(Internet Control Message Protocol 互联网控制报文协议)、ARP(Address Resolution Protocol 地址解析协议)、IRP(Route Information Protocol 路由信息协议)、IGMP(Internet Group Management Protocol 互联网组管理协议)

网络接口层

网络接口层用来处理连接网络硬件与链路的部分。包括控制操作系统、硬件设备驱动、网络适配器(NIC)及光纤等。
属于该层的协议有 FDDI(Fiber Distributed Data Interface 光纤分布式数据接口)、SLIP(Serial Line Internet Protocol 串行线路网际协议)、PPP(Point to Point Protocol 点对点协议)、IEEE802.1(802 LAN/MAN 体系结构与互连、安全、总体网络管理、MAC & LLC 层 协议)、IEEE802.3(ETHERNET 以太网标准)、IEEE802.11(WIRELESS LOCAL AREA NETWORKS 无线局域网标准 WLAN Wi-Fi) IEEE802.15.1(Bluetooth 蓝牙)IEEE802.15.4(ZigBee基于此标准)等

HTTP报文由哪些元素构成

HTTP报文包括请求报文和响应报文

请求报文 包括 请求方法 URI 协议版本 请求首部字段 内容实体 构成

1
2
3
4
5
6
7
POST /form/entry HTTP/1.1
Host: example.com
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 16

name=userName&age=16

响应报文 包括 协议版本 状态码 原因短语 创建响应的时间 响应首部字段 主体 构成

1
2
3
4
5
6
7
HTTP/1.1 200 OK
Date: Thu Apr 22 2021 00:08:31 GMT
Content-Length: 3620
Content-Type: text/html

<html>
......

HTTP Method 是区分大小写的,而 Header 是不区分的。

method 请求方法

HTTP/1.1 支持请求的方法如下:

请求方法 含义
GET GET方法用来请求访问已被URI识别的资源
POST POST方法用来传输报文主体部分
PUT PUT方法用来传输文件,但PUT方法自身不带验证机制,所以一般web网站不使用该方法
DELETE DELETE方法用来删除文件,同PUT方法作用相反,但因为不带验证机制,所以一般也不使用
HEAD HEAD方法用来获取报文首部,不返回报文主体
OPTIONS OPTIONS方法用来询问服务器支持的方法
TRACE TRACE方法让web服务器将之前的请求通信返回给客户端,容易引起XST(Cross-Site Tracing)攻击,所以也不常用
CONNECT CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信

GET 和 POST 请求的区别可以参考 HTTP-get-post区别

URI 统一资源标志符

URI(Uniform Resource Identifier)是指访问资源所使用的协议类型名称。在 RFC2396 中定义。标准的URI协议有30多种,由 国际互联网资源管理的非盈利性社团 ICANN(Internet Corporation for Assigned Names and Numbers) 管理。

URI包括以下几个部分:

http://user:pass@www.example.com:80/dir/index.html?uid=1#ch1
协议名、登录信息、服务器地址、服务器端口号、带层次的文件路径、查询字符串、片段标志符

Connection & Keep-Alive 持久连接

为了减少TCP三次握手的消耗,HTTP/1.1默认采用了 Connection: keep-alive 的首部字段来复用TCP三次握手所建立的连接通道。持久连接让客户端的请求可以以管线化的方式发送,即并行的同时发送多个请求而不需要等待上一个请求响应。同时,多数浏览器会对同时发起的请求数量进行限制以防止对连接资源的消耗。Chrome 浏览器限制为 8 个请求。

同时,消息发送者可以通过发送 Keep-Alive: timeout=5, max=1000 设置超时时长和最大请求数。

TCP三次握手

TCP协议位于传输层,提供了可靠的字节流服务。为了准确无误的将数据送达目标处,TCP协议采用了三次握手的策略,在数据包送出后会通过 TCP 标志 SYNC(synchronize) 和 ACK(acknowledgement)向对方确认是否成功送达。
发送端首先发送一个带有 SYNC 标志的数据包给对方。接收端收到后,回传一个带有 SYNC/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,代表“握手”结束。

HTTP请求是无状态的,但某些情况下我们需要进行状态管理,比如用户登录场景。Cookie 技术通过在请求和响应报文中写入 cookie 信息来控制客户端的状态。
Server端可以在响应报文中通过 Set-Cookie 的首部字段来通知客户端添加 cookie,客户端可以通过 document.cookie 获取和修改 cookie 相关信息。

更详细的介绍参见 HTTP Cookie

Content-Encoding 内容编码

内容编码指明了应用在实体内容上的编码格式,并保持实体原样压缩。内容编码后的实体由客户端接受并负责解码。 在请求报文首部中,添加 Accept-Encoding 字段表明客户端支持的内容编码形式,Server端在响应报文首部中添加 Content-Encoding 字段表明该次请求采用的内容编码形式。常见内容编码压缩方式如下:

内容编码方式 含义
gzip GNU zip
compress UNIX系统的标准压缩
deflate zlib
identify 不进行编码

Content-Type 内容类型

HTTP采用了MIME(Multipurpose internet Mail Extensions)来描述传输的内容类型。
MIME 信息是由 Internet Engineering Task Force (IETF) 在下面的文档中提供的:

  • RFC-822 Standard for ARPA Internet text messages
  • RFC-2045 MIME Part 1: Format of Internet Message Bodies
  • RFC-2046 MIME Part 2: Media Types
  • RFC-2047 MIME Part 3: Header Extensions for Non-ASCII Text
  • RFC-2048 MIME Part 4: Registration Procedures
  • RFC-2049 MIME Part 5: Conformance Criteria and Examples

常见的 Content-Type 类型有如下:

文件扩展名 Content-Type 含义
.html text/html 超文本标记语言文本
.txt text/plain 普通文本
.gif image/gif GIF图形
.png image/png png图形
.jpeg,.jpg image/jpeg JPEG图形
.ico image/x-icon icon图形
.au audio/basic 声音文件
.mpg,.mpeg video/mpeg MPEG文件
.avi video/x-msvideo AVI文件
.tar application/x-tar TAR文件
multipart/form-data web表单数据
.js application/javascript application/x-javascript js文件
.css text/css css文件
.json application/json json文件
multipart/form-data HTML表单

在缺失 MIME 类型或客户端认为文件设置了错误的 MIME 类型时,浏览器可能会通过查看资源来进行MIME嗅探。每一个浏览器在不同的情况下会执行不同的操作。因为这个操作会有一些安全问题,有的 MIME 类型表示可执行内容而有些是不可执行内容。服务器可以通过设置 X-Content-Type-Options: nosniff 响应头来阻止 MIME 嗅探。

内容协商

内容协商机制是指客户端和服务器就响应的资源内容进行交涉,然后提供给客户端最为合适的资源。内容协商字段会包含在请求报文的首部字段。包括: Accept、Accept-Charset、Accept-Encoding、Accept-Language、Content-Language

HTTPS协议升级机制

Upgrade-Insecure-Requests 是一个请求首部,用来向服务器端发送信号,表示客户端优先选择加密及带有身份验证的响应,并且它可以成功处理 upgrade-insecure-requests 的 CSP 指令。此请求头已添加为W3C Candidate Recommendation,Chrome 在 44.0.2403.130 版本将 Upgrade-Insecure-Requests 自动添加到 HTTP 请求的头部中。

1
2
3
GET / HTTP/1.1
Host: example.com
Upgrade-Insecure-Requests: 1

如果服务器同样支持 HTTPS 请求,则可以返回一个 带 LocationStatus-Code 为 3xx 的响应,将请求重定向到 HTTPS 版本。

1
2
Location: https://example.com/
Vary: Upgrade-Insecure-Requests

Status Code 状态码

参见 HTTP-状态码

HTTP/1.1 首部字段

首部字段分为四种 通用 请求 响应 实体

HTTP 首部字段参见 HTTP Headers

常见的有以下字段:

通用:

首部字段名 说明 例子
Cache-Control 控制缓存的行为 public;max-age=3600
Connection 逐跳首部、连接的管理 keep-alive
Date 创建报文的日期时间 Thu, 22 Apr 2021 16:38:01 GMT
Transfer-Encoding 制定报文主体的传输编码方式 chunked
Upgrade 升级为其他协议 TLS/1.0,HTTP/1.1

请求:

首部字段名 说明 例子
Accept 用户代理可处理的媒体类型 text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Charset 优先的字符集
Accept-Encoding 优先的内容编码 gzip, deflate, br
Accept-Language 优先的语言(自然) zh-CN,zh;q=0.9
Host 请求资源所在服务器 mangon.cn
If-Match 比较实体标记(ETag)
If-Modify-Since 比较资源的更新时间
If-None-Match 比较实体标记(与If-Match相反)
User-Agent HTTP客户端程序的信息 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
Upgrade-Insecure-Requests 表示客户端优先选择加密及带有身份验证的响应 Upgrade-Insecure-Requests: 1

响应:

首部字段名 说明 例子
ETag 资源的匹配信息 ETag: 61d64f3e-1f2
Location 令客户端重定向至指定URI Location: HTTPS://example.com:443/
Server HTTP服务器的安装信息 Server: nginx/1.16.1
Vary Vary 决定了对于未来的一个请求头,应该用一个缓存的响应还是向源服务器请求一个新的回复 Vary: Upgrade-Insecure-Requests
X-Frame-Options 用来给浏览器 指示允许一个页面 可否在 <frame>, <iframe>, <embed> 或者 <object> 中展现的标记。主要是为了防止 点击劫持 攻击 X-Frame-Options: <deny|sameorigin|allow-from uri>
X-XSS-Protection X-XSS-Protection 响应头是 Internet Explorer,Chrome 和 Safari 的一个特性,当检测到跨站脚本攻击(XSS)时,浏览器将停止加载页面。 X-XSS-Protection: 1; mode=block
Content-Security-Policy Content-Security-Policy允许站点管理者控制用户代理能够为指定的页面加载哪些资源,这主要是为了防止跨站脚本攻击(XSS) Content-Security-Policy: default-src ‘self’ http://example.com; connect-src ‘none’;
X-Content-Type-Options X-Content-Type-Options 相当于一个提示标志,被服务器用来提示客户端一定要遵循在 Content-Type 首部中对 MIME 类型 的设定,而不能对其进行修改。这就禁用了客户端的 MIME 类型嗅探行为 X-Content-Type-Options: nosniff
Strict-Transport-Security 告知浏览器只能通过HTTPS访问当前资源,chrome 可以在 chrome://net-internals/#hsts 查看hsts设置 Strict-Transport-Security: “max-age=63072000; includeSubdomains” always;

实体:

首部字段名 说明 例子
Allow 资源可支持的HTTP方法
Content-Encoding 实体主体适用的编码方式
Content-Language 实体主体的自然语言
Content-Length 实体主体的大小(字节)
Content-Location 替代对应资源的URI
Content-MD5 实体主体的报文摘要
Content-Type 实体主体的媒体类型
Expires 实体主体过期的日期时间
Last-Modified 资源的最后修改日期时间

CORS 相关字段参见 CORS

HTTPS

HTTP协议中没有加密机制,但可以通过和SSL(Secure Socket Layer 安全套接层)或 TLS(Transport Layer Security 安全传输层协议)的组合使用,加密 HTTP 协议的内容。与 SSL 组合使用的 HTTP 被称为 HTTPS(HTTP Secure 超文本传输安全协议)或 HTTP over SSL。

HTTPS 相对于 HTTP 多了三个方面

  • 报文加密
  • 服务器认证
  • 完整性保护

报文加密

SSL采用非对称的公开密钥加密(Public-key cryptography)的加密处理方式,加密算法是公开的,公有密钥(public key)是公开的,用来加密,私有密钥(private)是保密的,用来解密。

服务器认证

为了证明公有密钥的正确性,我们需要由数字证书认证机构(CA Certificate Authority)和其相关机关颁发的公开密钥证书。
多数浏览器开发商发布版本时,会事先在内部植入常用认证机关的公开密钥。

  1. 服务器把自己的公开密钥登录至数字证书认证机构
  2. 数字证书认证机构用自己的私有密钥向服务器的公开密钥部署数字签名并颁发公钥证书
  3. 服务器向客户端传输数据时会带上服务器的公开密钥和数字证书认证机构的数字签名及公钥证书
  4. 客户端拿到服务器的公钥证书后,使用数字证书认证机构的公开密钥,向数字认证机构验证公钥证书上的数字签名,以确认服务器的公开密钥的真实性
  5. 客户端使用服务器的公开密钥对报文加密后发送给服务器
  6. 服务器用私有密钥对报文解密

完整性保护

HTTP 可以通过 MD5 和 SHA-1 等散列值校验的方法来验证报文完整,但都需要客户端用户亲自检查验证,而且无法保证结果正确,因为 PGP(Pretty Good Privacy) 和 MD5 本身也可能被改写。SSL 会对报文进行信息摘要和加密,一旦篡改无法解密,也就达到了完整性保护的作用。

存在的问题

虽然 HTTPS 解决了 HTTP 存在的很多问题,但 HTTPS 也不是万能的,也存在一些问题

认证机构私钥丢失

2011年7月,荷兰一家名叫 DigiNotar 的认证机构遭到入侵,颁布了多个网站的伪造证书。因为伪造证书有正规认证机构的数字签名,所以浏览器会判定该证书是正当的。虽然有可以将证书无效化的证书吊销列表(Certificate Revocation List CRL)机制,以及从客户端删除根证书颁发机构(Root Certificate Authority RCA)的对策,但距离生效都需要一定时间。

自认证

使用 OpenSSL 这套开源程序,每个人都可以构建一套属于自己的认证机构,从而给自己颁发服务器证书。

处理速度比 HTTP 慢

HTTPS 需要经过 SSL 层,额外的一层通信导致速度会比HTTP要慢 2-100 倍。另外 SSL层必须进行加密处理,在服务器和客户端都需要进行加密运算,会比 HTTP 消耗更多的资源。

证书开销

要进行 HTTPS 通信,证书是必不可少的,想要获得 CA 认证的证书,需要向 CA 机构支付一定的费用,证书价格可能会根据不同认证机构略有不同,通常一年费用在上千人民币。

HTTP2

HTTP2 协议于 2015 年发布,由 RFC7540 和 RFC7541 两个规范组成,它基于 Google SPDY3 协议,主要在性能上进行了改进。

HTTP2 特性

  1. 二进制分帧层 (Binary Framing Layer)
    帧是数据传输的最小单位,以二进制传输代替原本的明文传输,原本的报文消息被划分为更小的数据帧

  2. 多路复用 (MultiPlexing)
    在一个 TCP 连接上,我们可以向对方不断发送帧,每帧的 stream identifier 会标明这一帧属于哪个流,然后在对方接收时,根据 stream identifier 拼接每个流的所有帧组成一整块数据。
    把 HTTP/1.1 每个请求都当作一个流,那么多个请求变成多个流,请求响应数据分成多个帧,不同流中的帧交错地发送给对方,这就是 HTTP/2 中的多路复用。

  3. 服务端推送 (Server Push)
    浏览器发送一个请求,服务器主动向浏览器推送与这个请求相关的资源,这样浏览器就不用发起后续请求。同时,客户端也有权利选择是否接收,如果资源已经缓存,浏览器可以通过发送 RST_STREAM 帧来拒收,主动推送也遵守同源策略。

  4. 基于 HPACK 算法的 Header 压缩
    使用 HPACK 算法(一种基于静态表、动态表和 Huffman 编码的编码算法)来压缩首部内容,避免了 header 字段数量多时每次都需要重复传输几百到几千字节的情况。

  5. 应用层的重置连接
    对于 HTTP/1 来说,是通过设置 tcp segment 里的 reset flag 来通知对端关闭连接的。这种方式会直接断开连接,下次再发请求就必须重新建立连接。HTTP/2 引入 RST_STREAM 类型的 frame,可以在不断开连接的前提下取消某个 request 的 stream,表现更好。

  6. 请求优先级设置
    HTTP/2 里的每个 stream 都可以设置依赖 (Dependency) 和权重,可以按依赖树分配优先级,解决了关键请求被阻塞的问题

  7. 流量控制
    每个 http2 流都拥有自己的公示的流量窗口,它可以限制另一端发送数据。对于每个流来说,两端都必须告诉对方自己还有足够的空间来处理新的数据,而在该窗口被扩大前,另一端只被允许发送这么多数据。

  8. HTTPS
    强制必须使用 HTTPS

在HTTP2中不再适用的优化方法

  1. 域名分片
    HTTP/2 对于同一域名使用一个 TCP 连接足矣,过多 TCP 连接浪费资源而且效果不见得一定好,而且资源分域会破坏 HTTP/2 的优先级特性,还会降低头部压缩效果

  2. 资源合并
    资源合并会不利于缓存机制,而且单文件过大对于 HTTP/2 的传输不好,尽量做到细粒化更有利于 HTTP2 传输

  3. 资源内联
    HTTP/2 支持 Server-Push,相比较内联优势更大效果更好,而且内联的资源不能有效缓存,如果有共用,多页面内联也会造成浪费

HTTP3

HTTP3 于 2018 年发布,它基于 Google 的 QUIC 协议,采用 UDP 协议进行传输,它主要解决了以下问题:

  • HTTP3 基于 UDP 协议重新定义了连接,在 QUIC 层实现了无序、并发字节流的传输,解决了队头阻塞问题(包括基于QPACK解决了动态表的队头阻塞)
  • HTTP3 重新定义了 TLS 协议加密 QUIC 头部的方式,既提高了网络攻击成本,又降低了建立连接的速度(仅需1个 RTT 就可以同时完成建链与密钥协商)
  • HTTP3 将 Packet、QUIC Frame、HTTP3 Frame 分离,实现了连接迁移功能,降低了 5G 环境下高速移动设备的连接维护成本

HTTP3特性

  1. 0-RTT(0 Round-trip Time)
    在一次 TCP 连接中,需要进行3次握手(3-RTT),即使会话复用也需要至少2个RTT,QUIC 协议是建立在 UDP 的基础上的,在大部分情况下,只有在首次连接时需要 1 RTT,之后的链接只需要0-RTT。

  2. 基于 QUIC Stream 的多路复用
    HTTP3 采用 UDP 作为传输层,又通过 QUIC 层实现了多路复用,保证实现数据流无序的并发传输和有序的交付。在 HTTP3 中,同一条 QUIC 连接上可以创建多个 stream 来发送多个 HTTP 请求,一个连接上的多个 stream 之间没有依赖,不会像 TCP 中存在队头阻塞。

  3. 连接迁移(Connection Migration)
    TCP 基于 IP 和端口号识别客户端和服务器,在多变的移动端网络环境下会频繁的发起 TCP 连接。QUIC 通过基于连接上下文的 Connection ID 识别连接,无论网络环境如何变化,ID 不变就可以迅速连接上。

  4. 基于 QPACK 算法的 header 编码
    HTTP3 中使用了类似 HPACK 算法的 QPACK 算法来进行 header 编码,旨在解决队头阻塞的问题

  5. 加密认证的报文
    TCP 协议 header 没有经过加密和认证,在网络传输过程中容易被中间网络设备篡改、注入或窃听。QUIC 的传输单位是 Packet,加密单元也是 Packet,有效的降低了安全风险。

  6. 前向纠错机制(Forward Error Correction, FEC)
    QUIC 使用前向纠错来增加协议的容错性。一段数据被切分为 10 个包后,对每个包进行异或运算,结果作为 FEC 包和数据包一起传输,如果有一个数据包丢失,可以根据剩余的 9 个包来推算出丢失的包数据,也即通过适当的数据冗余减少数据重传的操作。