概述
HTTP是互联网上应用最为广泛的一种网络协议,有名超文本链接协议。我们在开发中请求数据,发送数据都会用到HTTP协议。
与HTTP相关的协议
与HTTP相关联的协议有很多,其中TCP、IP、DNS尤为重要。
IP:网际协议
作用:把各种数据包传送给对方。
而要保证数据传输到对方那里,需要两个重要条件,IP地址和电脑地址(网卡地址)。
ARP:是一种用以解析地址的协议,根据通信方的IP地址就可以反查出对应的电脑地址。
TCP
作用于传输层,提供可靠的字节流服务。
具体参考三四握手、四次挥手
DNS
作用:作用于应用层,提供域名到IP地址之间的解析服务。
DNS协议提供通过域名查找IP地址,或者通过IP地址查找匿名服务。
客户端和服务端通信HTTP做了什么
HTTP报文
- 请求报文:请求方法、请求URI、协议版本、可选的请求首部字段、内容实体构成的。
- 响应报文:协议版本、状态码、解释状态码的原因短语、可选的响应首部
- 通知报文
不保存状态
HTTP是一种无状态协议。自身不对请求和响应之间的通信状态进行保存。HTTP/1.1虽然是无状态协议,但为了实现期望的保持状态功能,引入了Cookie技术。有了Cookie在使用HTTP协议通信,就可以管理状态了。
Cookie
Cookie是通过在请求和响应报文中写入Cookie信息来控制客户端的状态。根据服务端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie.当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值后发送出去(由于我是做iOS端的,不太了解Web这块,我所在公司的项目是手动存储Cookie的,具体是否会在第二次请求时自动发送,有待验证)。
持久链接
HTTP/1.1和部分HTTP/1.0支持持久链接,也成为HTTP keep-alive,持久链接的特点就是只要任意一方没有明确提出断开链接,则保持TCP链接状态。
管线化
持久连接使得多数请求以管线化方式发送成为可能。从前发送请求需要等待并且受到相应,才能发送下一个请求。管线化技术出现后,不需要等待响应就可以直接发送下一个请求。
WebSocket
一旦Web服务器与客户单建立起WebSocket协议的通信连接,之后所有的通信都依靠这个专用协议进行。通信过程可以相互发送JSON、XML、HTML或者图片等任意格式数据。
主要特点
- 推送功能
- 减少通信量(TCP连接消耗、WebSocket首部信息很小,通信量小)
期盼已久的HTTP/2.0
HTTP/2.0是在SPDY基础上行程的下一代互联网通信协议。HTTP/2.0的目的是支持请求与相应的多路复用来减少延迟,并且通过压缩HTTP首部字段将协议开销降低,同时增加请求优先级和服务端推送支持。
二进制分帧层
二进制分帧层,是HTTP/2.0性能增强的核心。
HTTP/1.x在应用层以纯文本的形式进行通信,HTTP/2.0将所有的传输信息分割为更小的消息和帧,并对它们采用二进制格式编码。所以,客户端和服务端都需要引入新的二进制编码和解码机制。
帧(frame)
HTTP/2.0通信的最小单位,包括帧首部、流标识符、优先值等。
其中,帧类型又分为:
- DATA:用于传输HTTP消息体;
- HEADERS:用于传输首部字段;
- SETTINGS:用于约定客户端和服务端的配置数据。比如设置初识的双向流量控制窗口大小;
- WINDOW_UPDATE:用于调整个别流或个别连接的流量;
- PRIORITY:用于指定或重新指定引用资源的优先级;
- RST_STREAM:用于通知流的非正常中指。
- PUSH_PROMISE:服务端推送许可。
- PING:用于计算往返时间。
- GOAWAY:用于通知对端停止在当前连接中创建流。
消息(message)
消息是指逻辑上的HTTP消息(请求/响应)。一系列数据帧组成了一个完整的消息。比如一系列DATA帧和一个HEADERS帧组成了请求消息。
流(stream)
流是连接中的一个虚拟信道,可以承载双向消息传输。每个流有唯一证书标识符。为了防止两断流的ID冲突,客户端发起的流具有奇数ID,服务端发起的流具有偶数ID。
所有HTTP/2.0通信都在一个TCP连接上完成,这个链接可以承载任务数量的双向数据流Stream。每个数据流以消息的形式发送,而消息由一或者多个帧组成,这些帧可以乱序发送,然后根据每个帧首部的流标识符重新组装。
二进制分帧层保留了HTTP的语义不受影响,包括首部、方法等,在应用层来看,和HTTP 1.x没有差别。同时,所有同主机的通信能够在一个TCP连接上完成。
多路复用共享连接
基于二进制分帧层,HTTP/2.0可以在共享TCP连接的基础上,同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义,交错发送出去,最后在另一端根据流ID和首部将它们重新组合起来。
对比HTTP/1.x和HTTP/2.0,假设不考虑1.x的pipeline机智,双方四层是一个TCP连接,客户端向服务端发起三个图片请求。
- HTTP/1.x发起的是串行,即image1返回后才能发起image2,image2返回后才能发起image3。
- HTTP/2.0建立一条TCP连接后,并行传输3个数据流,客户端向服务端错乱发送stream1-3的一系列DATA帧,与此同时,服务端已经在返回stream1的DATA帧
HTTP/2.0成功解决了HTTP/1.X的队首阻塞问题(TCP阻塞仍无法解决),同事,也不需要通过pipeline机智管理多条TCP连接来实现并行请求与相应。减少了TCP连接数对服务器性能也有较大提升。
请求优先级
流可以带有一个31bit的优先级:
- 0:表示最高哦优先级
- 2^31-1:表示最低优先级
客户端明确指定优先级,服务端可以根据这个优先级作为依据交互数据,但是在用优先级时需要注意以下问题: - 服务端是否支持请求优先级
- 是否会引起队首阻塞问题,比如高优先级的响应慢阻塞其他资源请求。
服务端推送
HTTP/2.0增加了服务端推送功能,服务端可以根据客户端的请求,提前返回多个响应,推送额外的资源给客户端。
PUSH_PROMISE帧是服务端向客户端有意推送的资源信号。
- 如果客户端不需要服务端Push,可在SETTINGS帧中设定服务端流的值为0,禁用此功能。
- PUSH_PROMISE帧中只包含预推送资源的首部。如果客户端对PUSH_PROMISE帧没有意见,服务端在PUSH_PROMISE帧后发送响应的DATA帧开始推送资源。如果客户端已经缓存该资源,不需要再推送,可以选择拒绝PUSH_PROMISE帧。
- PUSH_PROMISE必须遵循请求-响应原则,只能借着对请求的响应推送资源。
首部压缩
HTTP/1.x每一次通信都会鞋带首部信息用描述资源属性。HTTP/2.0在客户端和服务端之间使用“首部表”来跟踪和存储之前发的键值对。首部表在连接中始终存在,新增的键值对更新在结尾们不需要每次通信都携带首部。
另外,HTTP/2.0使用了首部压缩技术,压缩算法使用HPACHK。可让报头更紧凑,更快速传输。需要注意的是,HTTP/2.0关注的是首部压缩,而我们常用的gzip等是报文内容(body)压缩,二者不冲突。
一个完整的HTTP/2.0通信过程
客户端如何知道服务端是否支持HTTP/2.0?是否支持对二进制分帧层的编码和解码,所以,使用HTTP/2.0之前,必然存在协议协商过程。
基于ALPN的协商过程
支持HTTP/2.0的浏览器可以在TLS会话层自发完成和服务器的协议协商以确定是否使用HTTP/2.0通信。其原理是TLS 1.2中引入了扩展字段,允许协议扩展,其中ALPN协议用户客户端和服务端的协议协商过程。
服务端使用ALPN,监听443端口默认提高HTTP/1.1,并允许其他协议协商,比如SPDY和HTTP/2.0。
客户端可以在TLS握手Client Hello阶段表明资深支持HTTP/2.0。
服务端收到后,响应Server Hello,表示自己支持HTTP/2.0
基于HTTP的协商过程
客户端使用HTTP也可以开始HTTP/3.0通信。只不过因为HTTP/1.0和HTTP/2.0都使用同一个端口(80),又没有服务端是否是指HTTP/2.0的信息,此时客户端只能使用HTTP Upgrade机制(OKHttp,nghttp2等组件均可实现,也可以自己编码完成)通过协调确定适当的协议。
完整的通信过程
TCP连接建立->TLS握手->客户端向服务端发送SETTINGS帧,约定配置->流量控制->客户端想服务端发送HEADER帧->服务端返回配置->DATA帧传输数据
HTTP/2.0性能瓶颈
是不是启用HTTP 2.0后性能必然提升了?任何事情都不是绝对的,虽然总体而言性能肯定是能提升的。
我想HTTP 2.0会带来新的性能瓶颈。因为现在所有的压力集中在底层一个TCP连接之上,TCP很可能就是下一个性能瓶颈,比如TCP分组的队首阻塞问题,单个TCP packet丢失导致整个连接阻塞,无法逃避,此时所有消息都会受到影响。未来,服务器端针对HTTP 2.0下的TCP配置优化至关重要,有机会我们再跟进详述。
参考文献
《图解HTTP》
《HTTP 2.0 原理详细分析》