HTTP/1.0
- 支持GET和POST请求方式
- 本质上支持长连接,但是默认还是短连接,增加了keep-alive关键字来由短链接变成长连接
- HTTP的请求和回应格式也发生了变化,除了要传输的数据之外,每次通信都包含头信息,用来描述一些信息。
- 还增加了状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等
HTTP/1.1
HTTP1.1最大的变化就是引入了长链接,也就是TCP链接默认是不关闭的可以被多个请求复用。客户端或者服务器如果长时间发现对方没有活动就会关闭链接,但是规范的做法是客户端在最后一个请求的时候要求服务器关闭链接。对于同一个域名,目前浏览器支持建立6——8个长链接(chrom,6,firefox,8)。
不足
主要是连接缓慢,服务器只能按顺序响应,如果某个请求花了很长时间,就会出现请求队头阻塞
HTTP/2.0
特点
- 二进制分帧
- 首部压缩
- 流量控制
- 多路复用
- 请求优先级
- 服务器推送
二进制分帧
在不改变HTTP1.x的语义、方法、状态码。URL以及首部字段的情况下,HTTP2.0通过应用层(HTTP)和传输层(TCP)之间增加一个二进制分帧层来突破HTTP1.1的性能限制,改进传输性能,实现低延迟高吞吐量
- 帧:HTTP2.0通信的最小单位,所有帧都共享一个8字节的首部,其中包含帧的长度、类型、标志、还有一个保留位,并且至少有标识出当前帧所属的流的标识符,帧承载着特定类型的数据,如HTTP首部、负荷、等等。
- 消息:比帧大的通讯单位,是指逻辑上的HTTP消息,比如请求、响应等。由一个或多个帧组成
- 流:比消息大的通讯单位。是TCP连接中的一个虚拟通道,可以承载双向的消息。每个流都有一个唯一的整数标识符
- 首部压缩
HTTP1.1并不支持HTTP首部压缩,为此SPDY和HTTP2.0出现了。SPDY是用的是DEFLATE算法,而HTTP2.0则使用了专门为首部压缩设计的HPACK算法。
流量控制
HTTP2.0为数据流和连接的流量提供了一个简单的机制:
- 流量基于HTTP链接的每一跳进行,而非端到端的控制
- 流量控制基于窗口更新帧进行,即接收方广播自己准备接收某个数据流的多少字节,以及对整个链接要接收多少个字节。
- 流量控制有方向性,即接收方可能根据自己的情况为没个流乃至整个链接设置任意窗口大小
- 流量控制可以由接收方禁用,包括针对个别的流和针对整个链接。
- 帧的类型决定了流量控制是否适用于帧,目前只有DATA帧服从流量控制,所有其他类型的帧并不会消耗流量控制窗口的空间。这保证了重要的控制帧不会被流量控制阻塞
服务器推送
服务端根据客户端的请求,提前返回多个响应,推送额外的资源给客户端。
不足
- http2是基于tcp协议的,tcp协议在设计之初并非是以现在优质、高带宽的网络基础设施基础上设计的,他充分考虑了数据的可靠性,显得小心谨慎,在传输速率的表现,也已经跟不上现时的网络基础设施。未来是否有更优化的网络层协议发展出来,可以拭目以待,包括像基于udp协议的QUIC协议。个人认为下层协议还是由os内核来实现比较好,QUIC协议实现在应用层而非操作系统的内核层,始终是一个软肋。
- 大部分的http2实现和应用〈包括浏览器和web服务器),事实上都必须基于TLS(SSL)安全套接层。对于一个承载互联网内容的基础协议来说,这样的安全考量是合理的,也是必须的。有利就有弊,TLS的握手和数据加密过程必然给通信及通信双方带来一些负担。这些负担和额外的耗费,对于一些内部应用,比如说后端的微服务之间,有时候并不是必须的,是可以简化的。
- 由于现实世界已经基于http1建立起来,一些通讯链路上的基础设施,比如说http代理,暂不能支持http2,因此这会对http2的铺开造成阻碍,且这种阻碍可能是长期的过程。
- 由于http2是二进制的,传输又是多路复用的,在不同帧的设计上考虑到了压缩、优先级控制、流量控制、服务端推送,这导致http2的协议可以说比较复杂了。因此在协议的实现、应用的调试上将显然会比简单明文的http1增加一些难度。简单和直观,对于人类来说,具有天生的亲和力。
常见状态码
- 1xx: 指示信息——表示请求已接收,继续处理
- 2xx: 成功——表示请求已被成功接收
- 3xx: 重定向——表示要完成请求必须进行进一步操作
- 4xx: 客户端错误——表示请求有语法错误或请求无法实现
- 5xx: 服务端错误——表示服务器未能实现合法的请求
HTTP/3.0
出现背景
由于HTTP 2.0依赖于TCP,TCP有什么问题那HTTP2就会有什么问题。最主要的还是队头阻塞,在应用层的问题解决了,可是在TCP协议层的队头阻塞还没有解决。
TCP在丢包的时候会进行重传,前面有一个包没收到,就只能把后面的包放到缓冲区,应用层是无法取数据的,也就是说HTTP2的多路复用并行性对于TCP的丢失恢复机制不管用,因此丢失或重新排序的数据都会导致交互挂掉
为了解决这个问题,Google又发明了QUIC协议
特点
- 在传输层直接干掉TCP,用UDP替代
- 实现了一套新的拥塞控制算法,彻底解决TCP中队头阻塞的问题
- 实现了类似TCP的流量控制、传输可靠性的功能。虽然UDP不提供可靠性的传输,但QUIC在UDP的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些TCP中存在的特性
- 实现了快速握手功能。由于QUIC是基于UDP的,所以QUIC可以实现使用0-RTT或者1-RTT来建立连接,这意味着QUIC可以用最快的速度来发送和接收数据。
- 集成了TLS加密功能。目前QUIC使用的是TLS1.3
HTTPS
数字证书
验证服务器身份。如果没有验证的话,就可能被中间人劫持,假如请求被中间人截获,中间人把他自己的公钥给了客户端,客户端收到公钥就把信息发给中间人了,中间人解密拿到数据后,再请求实际服务器,拿到服务器公钥,再把信息发给服务器
服务器和CA机构分别有一对密钥(公钥和私钥),然后是如何生成数字证书的呢?
- CA机构通过摘要算法生成服务器公钥的摘要(哈希摘要)
- CA机构通过CA私钥及特定的签名算法加密摘要,生成签名
- 把签名、服务器公钥等信息打包放入数字证书,并返回给服务器
服务器配置好证书,以后客户端连接服务器,都先把证书发给客户端验证并获取服务器的公钥。
证书验证
- 使用CA公钥和声明的签名算法对CA中的签名进行解密,得到服务器公钥的摘要内容
- 再用摘要算法对证书里的服务器公钥生成摘要,再把这个摘要和上一步得到的摘要对比,如果一致说明证书合法,里面的公钥也是正确的,否则就是非法的
证书认证又分为单向认证和双向认证
- 单向认证:服务器发送证书,客户端验证证书
- 双向认证:服务器和客户端分别提供证书给对方,并互相验证对方的证书
不过大多数https服务器都是单向认证,如果服务器需要验证客户端的身份,一般通过用户名、密码、手机验证码等之类的凭证来验证。只有更高级别的要求的系统,比如大额网银转账等,就会提供双向认证的场景,来确保对客户身份提供认证性
加密过程
TLS实际用的是两种算法的混合加密。通过 非对称加密算法 交换 对称加密算法 的密钥,交换完成后,再使用对称加密进行加解密传输数据。这样就保证了会话的机密性。过程如下
- 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表
- 服务器把另一个随机数server-random、加密方法、公钥传给浏览器
- 浏览器又生成另一个随机数pre-random,并用公钥加密后传给服务器
- 服务器再用私钥解密,得到pre-random
- 浏览器和服务器都将三个随机数用加密方法混合生成最终密钥
这样即便被截持,中间人没有私钥就拿不到pre-random,就无法生成最终密钥。
对称加密算法
就是加密和解密使用同一个密钥。如AES、DES。加解密过程:
- 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表
- 服务器给浏览器返回另一个随机数server-random和双方都支持的加密方法
- 然后两者用加密方法将两个随机数混合生成密钥,这就是通信双方加解密的密钥
优点
- 内容加密,中间无法查看原始内容
- 身份认证,保证用户访问正确。
- 数据完整性,防止内容被第三方冒充或篡改
- 虽然不是绝对安全,但是现行架构下最安全的解决文案了,大大增加了中间人的攻击成本
不足
- 要钱,功能越强大的证书费用越贵
- 证书需要绑定IP,不能在同一个IP上绑定多个域名
- https双方加解密,耗费更多服务器资源
- https握手更耗时,降低一定用户访问速度(优化好就不是缺点了)
TLS1.2握手
- 浏览器给服务器发送一个随机数client-random、TLS版本和一个支持的加密方法列表
- 服务器生成一个椭圆曲线参数server-params、随机数server-random、加密方法、证书等传给浏览器
- 浏览器又生成椭圆曲线参数client-params,握手数据摘要等信息传给服务器
- 服务器再返回摘要给浏览器确认应答
这个版本不再生成椭圆曲线参数cliend-params和server-params,而是在服务器和浏览器两边都得到server-params和client-params之后,就用ECDHE算法直接算出pre-random,这就两边都有了三个随机数,然后各自再将三个随机加密混合生成最终密钥
TLS1.3握手
在TLS1.3版本中废弃了RSA算法,因为RSA算法可能泄露私钥导致历史报文全部被破解,而ECDHE算法每次握手都会生成临时的密钥,所以就算私钥被破解,也只能破解一条报文,而不会对之前的历史信息产生影响。目前主流都是用ECDHE算法来做密钥交换的
- 浏览器生成client-params、和client-random、TLS版本和加密方法列表发送给服务器
- 服务器返回server-params、server-random、加密方法、证书、摘要等传给浏览器
- 浏览器确认应答,返回握手数据摘要等信息传给服务器
简单说就是简化了握手过程,只有三步,把原来的两个RTT打包成一个发送了,所以减少了传输次数。这种握手方式也叫1-RTT握手
继续握手优化可以使用会话复用