关于HTTP相关协议的一些总结

粗浅概括

  • HTTP - TCP
  • HTTPS - TCP + TLS
  • SPDY -> TCP + TLS + 多路复用、头部压缩等特性 –> 发展成 HTTP/2
    • SPDY是Speedy的音,是更快的意思
  • HTTP/2 - TCP + TLS(理论上可选) + 多路复用、头部压缩等特性
  • QUIC - UDP –> 发展成 HTTP/3
  • HTTP/3 - UDP

其他基础

  • RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。

HTTP

  • 请求-响应模式(半双工)
  • 安全问题

“队头堵塞” (线头阻塞)(Head-of-line blocking)(HOLB)

  • HTTP 1.1 默认启用长TCP连接,但所有的请求-响应都是按序进行的(串行发送和接收)
  • HTTP 1.1 的管道机制:客户端可以同时发送多个请求,但服务端也需要按请求的顺序依次给出响应的;
  • 客户端在未收到之前所发出所有请求的响应之前,将会阻塞后面的请求(排队等待),这称为”队头堵塞”

管道机制(Pipelining)

  • 在管道机制下,服务端如何控制按顺序返回响应的?
    • HTTP是应用层协议,当然由各个应用程序按照规范自行实现了
    • 比如使用nginx,或jetty等,若服务端需要支持管道机制,都要底层逻辑自行实现,避免暴露给业务层
    • 那么因为要按顺序响应,那么当最前的请求的处理较慢时,同样会对服务端产生阻塞。
  • Pipelining需要客户端和服务端同时支持
  • 几乎所有的浏览器都是默认关闭或者不支持Pipelining的:对性能的提高有限、大文件会阻塞优先级更高的小文件等
  • 只有GET和HEAD要求可以进行管线化,而POST则有所限制

HTTPS

  • HTTPS(HTTP over TLS/SSL),TLS/SSL(会话层)

  • SSL(Secure Socket Layer)是安全套接层,TLS(Transport Layer Security)是传输层安全协议,建立在SSL3.0协议规范,是 SSL3.0 的后续版本。

  • TLS可以用在TCP上,也可以用在无连接的UDP报文上。协议规定了身份认证、算法协商、密钥交换等的实现。

  • SSL是TLS的前身,现在已不再更新

jks、pfx和cer 证书文件

  • jks是JAVA的keytools证书工具支持的证书私钥格式。
  • pfx是微软支持的私钥格式。
  • cer是证书的公钥。

权威证书颁发的公钥匙一般是预装的

  • SSL/TLS协议详解(中)——证书颁发机构

  • 当我们安装浏览器或操作系统时,将会附有一组证书颁发机构,例如DigiCert。当浏览器自带DigiCert时,这意味着浏览器具有DigiCert的公钥,网站可以向DigiCert索取证书和签名。因此,DigiCert将使用DigiCerts私钥在服务器证书上进行加密签名。当我们发起连接时,服务器将发送嵌入了其公钥的证书。由于浏览器具有DigiCert的公钥,因此可以在服务器证书上验证DigiCert的签名,同时也说明证书上写的服务器的公钥是可信的。

  • 根据RSA的加密原理,如果用CA的公钥解密成功,说明该证书的确是用CA的私钥加密的,可以认为被验证方是可信的。

HTTP/2

  • 全双工
  • 二进制格式传输、多路复用、header压缩、服务端推送、优先级和依赖关系、重置、流量控制

多路复用(Multiplexing)

  • 客户端发送多个请求和服务端给出多个响应的顺序不受限制, 避免”队头堵塞”
  • 每个数据流都有一个唯一的编号,从而让请求和响应对应起来
  • 客户端和服务器 可以发生信号取消某个数据流,并保持这个连接
  • 客户端还可以提升提升某个数据流优先级

加密

  • HTTP/2 沒规定一定要使用加密(例如 SSL),但目前大部分浏览器的 HTTP/2 都需要在 HTTPs上运行
  • gRPC 虽然使用 HTTP/2,但默认并没有需要配置加密证书

重用连接(针对浏览器)

  • 使用HTTP1.1协议,浏览器为了快速,针对同一域名设置了一定的并发数,稍微加快速度
  • 使用HTTP/2,浏览器针对同一个域名的资源,只建立一个tcp连接通道

头部压缩

  • 头部压缩也存在一些缺点 ,不管是Client还是Server,都要维护索引表,以确定每个索引值对应HTTP header的信息,通过占用更多内存换取数据量传输的减少(空间换时间)。

推送

  • Chrome将禁用HTTP/2服务器推送(Server Push)支持
    • 这功能逻辑本身就有问题,比如资源存放在单个业务服务器上,并行推送多个静态资源只会降低响应速度,性能不升反降。而对于前后端分离的业务来说,HTTP/2 本身就支持多路复用,server push 只能稍微降低浏览器解析 html 的时间,对现代浏览器来说性能提升可以忽略不计。

HTTP/3

  • HTTP/1.x 有连接无法复用、队头阻塞、协议开销大和安全因素等多个缺陷

  • HTTP/2 通过多路复用、二进制流、Header 压缩等等技术,极大地提高了性能,但是还是存在着问题的

  • QUIC 基于 UDP 实现,是 HTTP/3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议

  • HTTP3.0,也称作HTTP over QUIC。HTTP3.0的核心是QUIC(读音quick)协议,由Google在2015年提出的SPDY v3演化而来的新协议,传统的HTTP协议是基于传输层TCP的协议,而QUIC是基于传输层UDP上的协议,可以定义成:HTTP3.0基于UDP的安全可靠的HTTP2.0协议。

  • 在网络条件较差的情况下,HTTP/3在增强网页浏览体验方面的效果非常好

  • TCP从来就不适合处理有损无线环境中的数据传输

  • TCP中的行头阻塞

TCP的限制

  1. TCP可能会间歇性地挂起数据传输
    • TCP流的行头阻塞(HoL): 序列号较低的数据段丢包问题,导致阻塞
  2. TCP不支持流级复用
  3. TCP会产生冗余通信
    • TCP连接握手会有冗余的消息交换序列,即使是与已知主机建立的连接也是如此。

新特性

  • 选择UDP作为底层传输层协议。抛弃TCP的缺点(TCP传输确认、重传慢启动等),同时。此外QUIC是用户层协议,不需要每次协议升级时修改内核;
  • 流复用和流控:解决了行头阻塞问题。
  • 灵活的拥塞控制机制、更好的错误处理能力、更快的握手
  • 新的HTTP头压缩机制,称为QPACK,是对HTTP/2中使用的HPACK的增强(QUIC流是不按顺序传递的,在不同的流中可能包含不同的HTTP头)

采用HTTP/3的限制

  • 不仅涉及到应用层的变化,还涉及到底层传输层的变化
  • UDP会话会被防火墙的默认数据包过滤策略所影响
  • 中间层,如防火墙、代理、NAT设备等需要兼容
  • 需迫使中间层厂商标准化
  • HTTP/3在现有的UDP之上,以QUIC的形式在传输层处理,增加了HTTP/3在整个协议栈中的占用空间。这使得HTTP/3较为笨重,不适合某些IoT设备
  • NGINX和Apache等主流web服务器需要支持

Q&A

HTTP 与 TCP backlog关系

  1. 没直接关系
  2. HTTP是应用层协议,TCP backlog 是应用程序在操作系统层接收tcp连接的队列数
  3. 比如tomcat,作为一个HTTP应用服务,TCP backlog对应其acceptCount的配置

关于 HTTP keepalive

  1. keepalive 是否开启服务端控制还是客户端控制?
    • keepalive可以由双方共同控制,需要双方都开启才能生效,HTTP1.1客户端默认开启,客户端想关闭可以通过设置Connection: Close,服务端同样想关闭可以设置Connection: Close。双方哪方先收到Connection: Close 则由收到方关闭(前提是双方的实现都支持,比如telnet就不支持)
  2. keepalive的时间是由服务端控制还是客户端控制?
    • 时间主要还是由服务端控制,时间一到由服务端主动关闭,当然客户端如果有实现设置一定时间后,由客户端主动关闭也可以。一般的HTTPclient库都有提供相应的配置,设置关闭长期不使用的连接,如connectionManager.closeIdleConnections(readTimeout * 2, TimeUnit.MILLISECONDS);
    • HTTPs://my.oschina.net/greki/blog/83350
  3. keepalive时间一到,是由客户端主动关闭还是服务端主动关闭?
    • 哪方的时间短,由哪一方来关闭,除非双方的实现有更明确的协议
  4. 如果客户端不是HTTPclient,使用telnet连接服务端?
    • telnet客户端除了连接时进行三次握手,用来发送数据接收数据,基本无其他实现逻辑。即接收到服务器的响应之后,不会有相关HTTP协议的处理。

HTTP keepalive VS TCP keepalive

  • HTTPs://zhuanlan.zhihu.com/p/385597183; HTTPs://juejin.cn/post/6992845852192702477
  • HTTP 的 Keep-Alive,是由应用层(用户态) 实现的,称为 HTTP 长连接;
  • TCP 的 Keepalive,是由 TCP 层(内核态) 实现的,称为 TCP 保活机制;
  • HTTP协议的Keep-Alive意图在于短时间内连接复用,希望可以短时间内在同一个连接上进行多次请求/响应。
  • TCP的KeepAlive机制意图在于保活、心跳,检测连接错误。当一个TCP连接两端长时间没有数据传输时(通常默认配置是2小时),发送keepalive探针,探测链接是否存活。
  • tcp的keepalive是在ESTABLISH状态的时候,双方如何检测连接的可用行。而HTTP的keep-alive说的是如何避免进行重复的TCP三次握手和四次挥手的环节。
  • 总之,HTTP的Keep-Alive和TCP的KeepAlive不是一回事。

Chrome中HTTP下载续传原理

HTTP连接复用时,同一个连接上的多个请求和响应如何对应上?

  • “队头堵塞”(Head-of-line blocking):所有的请求-响应都是按序进行的(HTTP)
  • 多路复用(Multiplexing):每个数据流都有一个唯一的编号,从而让请求和响应对应起来(HTTP/2)

可以外网使用HTTP/3,再转发到内网的HTTP服务?

  • 上层nginx使用HTTP3,下层应用服务器(如spring boot jetty等)还是使用HTTP,其实理论上是可以的。nginx转发时要由接受到的udp包改成tcp发送。(内网丢包概率一般应该比外网丢包低很多),如果采用这种转发方式,这就意味着内网无法使用四层负载转发,因为底层协议不一样(udp和tcp)
  • 现在主流的代理服务Nginx/Apache都没有实现QUIC,一些比较小众的代理服务如Caddy就实现了

使用HTTPS还存在中间人攻击?

  • 结论:可以避免。只要不信任不安全的HTTPs网站,就不会被中间人攻击

  • 中间人攻击:HTTPs://urlify.cn/zQj6f2

  • 既然证书是公开的,如果要发起中间人攻击,我在官网上下载一份证书作为我的服务器证书,那客户端肯定会认同这个证书是合法的,如何避免这种证书冒用的情况?
    其实这就是非加密对称中公私钥的用处,虽然中间人可以得到证书,但私钥是无法获取的,一份公钥是不可能推算出其对应的私钥,中间人即使拿到证书也无法伪装成合法服务端,因为无法对客户端传入的加密数据进行解密。

  • 只要客户端是我们自己的终端,我们授权的情况下,便可以组建中间人网络,而抓包工具便是作为中间人的代理。

Q: 为什么需要证书?
A: 防止”中间人“攻击,同时可以为网站提供身份证明。

Q: 使用 HTTPS 会被抓包吗?
A: 会被抓包,HTTPS 只防止用户在不知情的情况下通信被监听,如果用户主动授信,是可以构建“中间人”网络,代理软件可以对传输内容进行解密。

扩展

cURL 发 HTTP/2请求

  1. Mac OS Curl HTTP/2 支持
    brew install curl --with-ngHTTP2
/usr/local/Cellar/curl/7.50.3/bin/curl --HTTP2 -kI  HTTPs://localhost:8443/user/1
HTTP/2 200
server: Jetty(9.3.10.v20160621)
date: Sun, 30 Oct 2016 02:08:46 GMT
content-type: application/json;charset=UTF-8
content-length: 23
  1. linux:HTTPs://www.sysgeek.cn/curl-with-HTTP2-support/

HTTP/3 握手优化

  • 1倍时延 = 一次单向传输时延 = 0.5 RTT
  • HTTPS 的 7 次握手以及 9 倍时延
  • HTTPS: 7 次握手以及 9 倍时延 (4.5 RTT); HTTP/3: 3 次握手以及 5 倍时延 (2.5 RTT)
    当客户端想要通过 HTTPS 请求访问服务端时,整个过程需要经过 7 次握手并消耗 9 倍的延迟。如果客户端和服务端因为物理距离上的限制,RTT 约为 40ms 时,第一次请求需要 ~180ms;不过如果我们想要访问美国的服务器,RTT 约为 200ms 时,这时 HTTPS 请求的耗时为 ~900ms,这就是一个比较高的耗时了。我们来总结一下 HTTPS 协议需要 9 倍时延才能完成通信的原因:

TCP 协议需要通过三次握手建立 TCP 连接保证通信的可靠性(1.5-RTT);
TLS 协议会在 TCP 协议之上通过四次握手建立 TLS 连接保证通信的安全性(2-RTT);
HTTP 协议会在 TCP 和 TLS 上通过一次往返发送请求并接收响应(1-RTT);
需要注意的是,本文对往返延时的计算都基于特定的场景以及特定的协议版本,网络协议的版本在不断更新和演进,过去忽略的问题最开始都会通过补丁的方式更新,但是最后仍然会需要从底层完成重写。

HTTP/3 就是一个这样的例子,它会使用基于 UDP 的 QUIC 协议进行握手,将 TCP 和 TLS 的握手过程结合起来,把 7 次握手减少到了 3 次握手,直接建立了可靠并且安全的传输通道,将原本 ~900ms 的耗时降低至 ~500ms,

Reference