计算机网络 — 透视 HTTP 协议

一、HTTP 是什么

超文本传输协议。HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。

二、HTTP 历史版本

1. HTTP/1.1 在 HTTP/1.0 上的改进

  • 使用 TCP 长连接的方式改善了 1.0 短连接造成的性能开销,1.1 中的连接都会默认启用长连接,不需要用什么特殊的字段指定,只要向服务器发送了第一次请求,后续的请求都会重复利用第一次打开的 TCP 连接,也就是长连接,在这个连接上收发数据;
  • 支持 管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

HTTP/1.1 还存在性能瓶颈:

  • 请求/响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 部分;
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多;
  • 服务器是按请求的顺序响应的,如果服务器响应慢,会导致客户端一直请求不到数据,造成队首阻塞;
  • 没有优先级控制;
  • 请求只能从客户端开始,服务器只能被动响应。

2. HTTP/2.0

二进制分帧

HTTP/2 采用二进制格式传输数据,而非 HTTP/1.x 的文本格式,二进制协议解析起来更高效。

头部压缩

HTTP/1.x 会在请求和响应中重复的携带不常改变的、冗长的头部数据,给网络带来额外的负担。

  • HTTP/2 在客户端和服务器端使用「首部表」来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送;
  • 首部表在 HTTP/2 的连接存续期内始终存在,由客户端和服务器共同渐进的更新;
  • 每个新的首部键值对要么追加到当前表的末尾,要么替换表中的值。

服务器推送

服务端可以在发送页面 HTML 时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 HTML 时再发送这些请求。

服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送 RST_STREAM 帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。

多路复用

HTTP/1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8 个的 TCP 链接请求限制。

而在 HTTP2 中:

  • 同域名下所有通信都在单个连接上完成;
  • 单个连接可以承载任意数量的双向数据流;
  • 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。

三、基础概念

1. 代理(Proxy)

代理(Proxy)是 HTTP 协议中请求方和应答方中间的一个环节,作为「中转站」,既可以转发客户端的请求,也可以转发服务器的应答。

代理有很多的种类,常见的有:

  1. 匿名代理:完全「隐匿」了被代理的机器,外界看到的只是代理服务器;
  2. 透明代理:在传输过程中是「透明开放」的,外界既知道代理,也知道客户端;
  3. 正向代理:靠近客户端,代表客户端向服务器发送请求;
  4. 反向代理:靠近服务器端,代表服务器响应客户端请求。

由于代理在传输过程中插入了一个「中间层」,所以可以再这个环节做很多有意思的事情,比如负载均衡、内容缓存、安全防护、数据处理等。

2. 负载均衡

四层负载均衡:工作在传输层上,基于 TCP/IP 协议的特性,例如 IP 地址、端口号等实现对后端服务器的负载均衡。

七层负载均衡:工作在应用层上,看到的是 HTTP 协议,解析 HTTP 报文里的 URI、主机名、资源类型等数据,再用适当的策略转发给后端服务器。

四、请求和响应报文

1. 请求报文

2. 响应报文

五、HTTP 方法

1. 常用方法

  1. GET:获取资源,可以理解为读取或者下载数据;
  2. HEAD:获取报文首部,和 GET 方法类似,但不返回报文实体主体部分;
  3. POST:传输实体主体,相当于写入或上传数据;
  4. PUT:上传文件,类似 POST;
  5. DELETE:删除文件;
  6. CONNECT:建立特殊的连接隧道;
  7. OPTIONS:查询支持的方法,会返回 Allow:GET, POST, HEAD, OPTIONS 这样的内容。

2. POST 和 PUT 的区别?

POST 表示的新建(create),而 PUT 则是修改(update)。可以对比 SQL,把 POST 理解成 INSERT,把 PUT 理解成 UPDATE。在实际应用中,PUT 用到的比较少。

3. 安全与幂等

安全

在 HTTP 协议中,所谓的 安全 是指请求方法不会破坏服务器上的资源,即不会对服务器上的资源造成实质的修改。按照这个定义,只有 GET 和 HEAD 方法是安全的,因为它们是只读操作。

幂等

幂等 实际上是一个数学用语,被借用到了 HTTP 协议里,意思是多次执行相同的操作,结果也都是相同的,即多次 「幂」 后结果 「相等」。

很显然,GET 和 HEAD 既是安全的也是幂等的,DELETE 可以多次删除同一个资源,效果都是「资源不存在」,所以也是幂等。POST 是新增数据,多次新增会创建多个资源,所以不是幂等的,而 PUT 是更新资源,多次更新一个资源,所以是幂等的。

六、状态码

服务器返回的 响应报文 中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。

  • 1XX:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
  • 2XX:成功,报文已经收到并被正确处理;
  • 3XX:重定向,资源位置发生变动,需要客户端重新发送请求;
  • 4XX:客户端错误:请求报文有误,服务器无法处理;
  • 5XX:服务器错误:服务器在处理请求时内部发生了错误。

1XX 信息

  • 100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。

2XX 成功

  • 200 OK
  • 204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
  • 206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。

3XX 重定向

  • 301 Moved Permanently :永久性重定向,此次请求的资源已经不存在了,需要改用新的 URI 再次访问。

  • 302 Found:临时重定向,请求的资源还在,但需要暂时用另一个 URI 来访问。
  • 303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
  • 304 Not Modified :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
  • 307 Temporary Redirect :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。

4XX 客户端错误

  • 400 Bad Request :请求报文中存在语法错误,通用的错误码。
  • 403 Forbidden :请求被拒绝。服务器禁止访问资源,原因可能多种多样,例如信息敏感、法律禁止等。
  • 404 Not Found:资源在服务器上未找到。

5XX 服务器错误

  • 500 Internal Server Error :服务器正在执行请求时发生错误,通用的错误码。

  • 503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

七、缓存

1. 优点

  • 缓解服务器压力;
  • 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近,例如浏览器缓存。

2. 实现方法

  • 让代理服务器进行缓存;
  • 让客户端浏览器进行缓存。

3. Cache-Control

HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。

3.1 禁止进行缓存

no-store 指令规定不能对请求或响应的任何一部分进行缓存。

Cache-Control: no-store

3.2 强制确认缓存

no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效时才能使用该缓存对客户端的请求进行响应。

Cache-Control: no-cache

3.3 私有缓存和公共缓存

private 指令规定了将资源作为私有缓存,只能被单独用户使用,一般存储在用户浏览器中。

Cache-Control: private

public 指令规定了将资源作为公共缓存,可以被多个用户使用,一般存储在代理服务器中。

Cache-Control: public

3.4 缓存过期机制

max-age 指令出现在请求报文,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。

max-age 指令出现在响应报文,表示缓存资源在缓存服务器中保存的时间。

Cache-Control: max-age=31536000

Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。

Expires: Wed, 04 Jul 2012 08:26:05 GMT
  • 在 HTTP/1.1 中,会优先处理 max-age 指令;
  • 在 HTTP/1.0 中,max-age 指令会被忽略掉。

4. 缓存验证

需要先了解 ETag 首部字段的含义,它是资源的唯一标识。URL 不能唯一表示资源,例如 http://www.google.com/ 有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。

ETag: "82e22293907ce725faf67773957acd12"

可以将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到该请求后,判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致,如果一致则表示缓存资源有效,返回 304 Not Modified。

If-None-Match: "82e22293907ce725faf67773957acd12"

Last-Modified 首部字段也可以用于缓存验证,它包含在源服务器发送的响应报文中,指示源服务器对资源的最后修改时间。但是它是一种弱校验器,因为只能精确到一秒,所以它通常作为 ETag 的备用方案。如果响应首部字段里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 OK。如果请求的资源从那时起未经修改,那么返回一个不带有实体主体的 304 Not Modified 响应报文。

Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT

八、HTTPS

HTTP 有以下安全性问题:

  • 使用明文进行通信,内容可能会被窃听;
  • 不验证通信方的身份,通信方的身份有可能遭遇伪装;
  • 无法证明报文的完整性,报文有可能遭篡改。

HTTPS 并不是新协议,而是 HTTP 先和 SSL(Secure Sockets Layer 安全套接层)/ TLS (Transport Layer Security 安全层传输协议) 通信,再由 SSL/TLS 和 TCP 通信。也就是说 HTTPS 使用了隧道进行通信。

通过使用 SSL,HTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。


1. HTTP 和 HTTPS 的区别

  • HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
  • 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。
  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 SSL 握手需要的 9 个包,所以一共是 12 个包。

2. 常用加密方式

对称加密

对称密钥加密(Symmetric-Key Encryption),加密和解密使用同一密钥。

非对称加密

非对称密钥加密,又称公开密钥加密(Public-Key Encryption),加密和解密使用不同的密钥。

公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。

非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确。

3. HTTPS 加密方式

HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。

参考