2019年8月底,我面向公司产研同事做了做了一次“HTTP协议”的技术分享,收到大家的点赞,最开心的当然是...
HTTP(HyperText Transfer Protocol)
全称“超文本标记语言”,由万维网联盟提出,互联网工程小组标准化的应用层协议。他的设计之初是用于Web浏览器和Web服务器的通信,浏览器向服务器发送请求,服务器再响应后结束了。
HTTP是无状态协议,每次请求和响应结束了之后服务器不会保留任何状态。

HTTP是基于TCP的应用层协议,这里就需要提到HTTP与网络模型的关系了:

国际化标准组织OSI在上世纪发布的“开放系统互联基本参考模型”,是种学术性的理想模型,刚开始得到了很多国家或组织的支持。但现今规模最大的,覆盖全网的英特网并未完全使用OSI标准,而是符合实际应用,层次分明合理,效率高的TCP/IP模型,成为了事实上的国际标准。简单说就是:能够垄断或占领市场的就是标准。
接下来就需要讲讲TCP和UDP了:

上图可以看出,TCP结构复杂而UDP则相反。以下对他们进行了全面的比较:

既然TCP是可靠、面向连接的协议,当然也就少不了握手了:

三次握手阶段详解(C为Client,S为Server,下同):
- C向S发送连接请求连接报文段,进入“同步已发送阶段”,等待S的确认。
- S收到C的SYN标志后,发送SYN和ACK标志,进入同步收到阶段。
- C收到了SYN和ACK标志后,进入已建立连接阶段,最后向S发送ACK标志的报文段(此时可以发送Data数据),S收到后进入已建立连接阶段。
为何需要三次握手?
这是为了保证双方能够建立可靠的连接,第一次握手只是为了告知S端我想请求,第二次握手是让C端建立连接,第三次握手让S端必须要知道C端建立了连接才是会建立连接,所以这三次握手不多不少。
四次挥手阶段详解:
- C向S发送连接释放报文段,并停止发送数据,寻求主动关闭连接,C进入“终止等待-1”状态,等待S的确认。
- S收到连接释放报文段后即发出确认,S进入“关闭等待”状态,这时TCP还处于半关闭状态:“即C没有数据要发送了,但S有数据要发送,C仍然要接收。一句话就是C关闭了但S还没关闭”。C收到S的确认后,就进入“终止等待-2”状态,等待S发出的连接释放报文段。
- 当S没有数据要发送给C后,其应用进程就通知TCP释放连接,发送释放报文段。这时S进入“最后确认”状态,等待C的确认。
- C收到S发出的释放报文段后,必须对此发出确认。然后进入到“时间等待”状态,C必须经过时间等待计时器设置的时间2MSL(一般为2分钟)后,C才彻底关闭TCP连接。
- S只要收到了C的确认,就会关闭TCP连接。
为什么C必须等待2MSL的时间才能关闭?
- 为了保证S能收到最后一个ACK报文段。若S没不到,会向C再次发送上一个报文段,等待时间重新计时。
- 为了防止“已失效的连接请求报文段”出现在本次连接中。在2MSL的持续时间中,能让所有产生的报文段都从网络中消失。使下一个新的连接中不会出现这种旧的连接请求报文段。
发展历史

目前主流的版本是HTTP/1.1和HTTP/2,HTTP/3由2018年标准化的全新一代协议,后面会讲到。
HTTP/1.1
请求和响应体结构

请求体和响应体除了第一行由区别,其余都是一样的。
头部域

方法

状态码

以上是HTTP核心的知识点,下面讲讲前端的跨域的CORS配置。
CORS
CORS全称“跨域资源共享”,W3C标准,目的是规避浏览器的同源策略。由于安全原因,浏览器只允许同源的Ajax请求。当响应头包含了正确的CORS配置时,浏览器允许向跨源服务器发Ajax请求,从而克服了Ajax只能同源使用的限制。从网站管理员到前后端人员都应该知晓CORS。
同源策略

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。限制范围:
- Cookie、LocalStorage 和 IndexDB 无法读取。
- DOM 无法获得。
- AJAX 请求不能发送。
两种请求
Ajax请求跨域时会被分为两种请求:简单请求和非简单请求,不符合简单请求条件的均为非简单请求。简单请求的条件:
- 三种方法之一:HEAD、GET、POST。
- 头信息不超出以下字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(不超出application/x-www-form-urlencoded、multipart/form-data、text/plain)。
浏览器对这两种请求的处理机制是不一致的。
头部域的CORS字段

CORS流程

跨域的Ajax请求和同源的Ajax请求完全一样,不同的是,当出现跨域的Ajax时,服务器需要设置CORS来告知浏览器允许访问该资源。CORS是跨域Ajax请求的根本解决办法。
Demo

后端通过维护允许跨域访问的列表,根据请求头部域的Origin来匹配并添加Access-Control-Allow-Origin。未匹配到,则响应头部域不带上Access-Control-Allow-Origin。
注意: 如果要发送Cookie(Access-Control-Allow-Credentials:true),Access-Control-Allow-Origin就不能设为星号*,必须指定明确的、与请求网页Origin一致的域名,否则浏览器会因不合法而禁止访问。
缓存控制
HTTP/1.0版本的浏览器缓存主要是通过Expires头部控制来实现的,它只能根据绝对时间来刷新缓存内容。HTTP/1.1版本新增了Cache-Control头部域,使得前端具备了强缓存和协商缓存机制,在Cache-Control存在的情况下,Expires会无效。
缓存控制字段 - Cache-Control

即使响应的是no-cache浏览器也会缓存资源,但是每次请求时都会向后端协商,更改则200,未更改则是304,所以no-cache可以用于协商缓存。
协商缓存字段 - Etag/Last-Modified

缓存控制流程

(蓝色虚线部分为启发式缓存)
缓存会分为强缓存和协商缓存:
- 当Cache-Control未过期直接从本地缓存读取,这是强缓存。
- 当Cache-Control过期后向后端请求时带上了If-None-Match或If-Modified-Since请求服务器进行决策,这是协商缓存。
我们应该为静态资源设置合理的Cache-Control响应字段。当没有Cache-Control时,浏览器会使用启发式算法来缓存资源,缓存时间通常是‘Date’减去‘Last-Modified’ 除以10 作为缓存时间,不同的浏览器实现方式可能会不一样。
缓存示例
第一次访问

第二次访问

Disk Cache是永久缓存至硬盘中;Memory Cache是临时缓存至内存中,浏览器关闭后则从Disk Cache读取缓存。
HTTPS
全称HyperText Transfer Protocol over Secure Socket Layer,基于安全套接字层的超文本传输协议。
为什么要HTTPS?
HTTP是明文的,有被窃听,篡改和冒充的风险。

Chrome已对不安全的HTTP网站禁用摄像头,定位,全屏,设备传感器等涉及隐私的API。接下来看看这把锁匙什么,为什么加了把锁会不一样。
加密算法
这把锁用到了两种加密算法,非对称加密算法和对称加密算法:

非对称加解密目前只能用来作对称密钥交换或者CA签名,不适合用来做应用层内容传输的加解密。
- 加解密同等数量的文件,非对称算法消耗的CPU资源是对称算法的1000倍以上,极端消耗CPU资源。
- 非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是2048位,意味着待加密内容不能超过256个字节。
HTTPS结构
SSL/TLS发展历史

TLS全称是传输层协议,是SSL的升级版,由互联网工程任务组IETF于1999标准化。
TLS1.2四次握手

握手过程:
- 客户端发送「Client hello」 请求连接。
- 服务端发送证书,协商加密算法。
- 客户端验证证书,成功后用之前协商好的加密算法生产对称密钥,用服务端发送的公钥加密该对称密钥,发送给服务端。
- 服务端用私钥解密客户端发送的加密的对称密钥,发送「Finished」结束握手。
- 之后两端用对称密钥加密和传送数据。
Session会话恢复

使用 TLS 1.2 需要两次往返( 2-RTT )才能完成握手。Session Ticket会在TLS第四次握手时发送给客户端,之后的TLS握手会带上“Session ID”,只需要一次往返。
为什么有单双向验证?
- 一般Web应用都是采用SSL单向认证的,原因很简单,用户数目广泛,且无需在通讯层对用户身份进行验证,一般都在应用逻辑层来保证用户的合法登入。
- 如果是企业应用对接,情况就不一样,可能会要求对客户端(相对而言)做身份验证。这时就需要做SSL双向认证,企业应用对接需要注意客户端的证书过期。
TLS1.3二次握手

TLS 1.3 是一个全新的 TLS 加密协议,相比 TLS 1.2 ,它既能提高各地互联网用户的访问速度,又能增强安全性。TLS 1.3 通过移除对老旧破损的密码协议的支持,来提高性能、效率和安全性。它还通过简化 TLS 握手来提高速度,使其只需要一次往返,后续无需握手即可恢复会话。
TLS1.3 于2018年标准化,目前兼容性不太好,感兴趣的同学可以去CanIUse查询。
HTTP/2
前身是SPDY,优化并解决了HTTP1.X 队头阻塞,效率低,头大(臃肿)等问题。
为什么需要HTTP/2?
- HTTP/1.1请求响应遵循先进先出,存在对头阻塞。
- 浏览器对网站的TCP连接由6-8个限制。
HTTP/2 消息结构:

通过双向数据流传输消息,消息由一或多个帧组成,帧为最小单位传输单位。
- 帧:HTTP/2最小的通信单位,二进制组成。帧具有优先级,可乱序发送,达到后可根据帧的首部流标识重新拼接成消息。
- 消息:HTTP请求或响应的消息,包括头部和消息主体。
- 流:虚拟连接通道,可以承载任意双向数据流,互不干扰,每个数据流以消息的形式发送,流具有优先级。
- 每个请求都可以带上优先级,两端会以最优的方式发送流,消息和帧。
多路复用:
- 同一个域名,同一个连接。
- 以流为基础,并发双向传输。

二进制分帧
HTTP/2采用二进制将消息分成帧传输数据,而非HTTP/1.x的文本格式。应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层,通过二进制将消息分成帧发送,更为高效。

首部压缩
HTTP/1.x 每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。HTTP/2 对消息头部采用HPACK进行压缩传输,首部只传输 “新的头信息”。
- 两端使用「首部表」来跟踪和存储之前发送的「键值对」,相同的不再发送。
- 「首部表」在连接中始终存在,两端渐进更新。
- 新的「键值对」替换或追加在末尾。

服务端推送
服务端向客户端主动推送并让其缓存多个资源,实现「一次请求,多个响应」。让服务器决定优先推送的内容,比前端对内嵌资源优化的手段更为高效。

服务端推送可以有哪些内容?
- 网页现需要的资源文件。
- 网页尚未缓存的动态资源文件。
- 用户可能访问的下一页。
服务端推送对比图:

兼容性
目前主流浏览器中只有IE10不兼容,如果不兼容IE10的话可以完全考虑全站使用HTTP/2。互联网工程任务组发布的HTTP/2标准是允许使用不安全的HTTP的,但各大浏览器厂商要求强制采用HTTPS。
普及率
目前普及率在40%左右,由2018年8月初的29%上升至2019年8月初的39%。
HTTP/3
基于QUIC协议的HTTP,于2018年经互联网工程任务组命名为HTTP/3。
QUIC是传输层协议,基于高效的UDP,整合了TCP、TLS、和HTTP/2的优点,并加以优化。

为什么需要HTTP/3?
- TCP太重,存在慢启动,握手成功起初会限制连接速度,当数据传输成功之后会慢慢提高传输速度。HTTP的性能关键在于低延迟,而不是高带宽。
- TCP存在队头阻塞。
特性一:1RTT - DH密钥交换算法
HTTP/2 的连接需要 3 RTT,如果考虑会话复用,即把第一次握手算出来的对称密钥缓存起来,那么也需要 2 RTT,更进一步的,如果 TLS 升级到 1.3,那么 HTTP/2 连接需要 2 RTT,考虑会话复用则需要 1 RTT。
HTTP/3 首次连接只需要 1 RTT,后面的连接更是只需 0 RTT,意味着客户端发给服务端的第一个包就带有请求数据,这一点 HTTP/2 难以望其项背。

QUIC 实现 0 RTT 的一个技术细节是使用了 DH密钥交换算法:

特性二:连接迁移
TCP 连接基于四元组(源 IP、源端口、目的 IP、目的端口),切换网络时至少会有一个因素发生变化,导致连接发生变化。当连接发生变化时,如果还使用原来的 TCP 连接,则会导致连接失败,就得等原来的连接超时后重新建立连接,所以我们有时候发现切换到一个新网络时,即使新网络状况良好,但内容还是需要加载很久。
QUIC 的连接不受四元组的影响,当这四个元素发生变化时,原连接依然维持。那这是怎么做到的呢?道理很简单,QUIC 连接不以四元组作为标识,而是使用一个 64 位的随机数,这个随机数被称为 Connection ID,即使 IP 或者端口发生变化,只要 Connection ID 没有变化,那么连接依然可以维持。
特性三:流量控制
TCP 会对每个 TCP 连接进行流量控制,流量控制的意思是让发送方不要发送太快,要让接收方来得及接收,不然会导致数据溢出而丢失,TCP 的流量控制主要通过滑动窗口来实现的。
QUIC 只需要建立一条连接,在这条连接上同时传输多条 Stream,好比有一条道路,两头分别有一个仓库,道路中有很多车辆运送物资。QUIC 的流量控制有两个级别:连接级别(Connection Level)和 Stream 级别(Stream Level)。
特性四:拥塞控制
拥塞控制的目的是避免过多的数据一下子涌入网络,导致网络超出最大负荷。QUIC 的拥塞控制与 TCP 类似,并在此基础上做了改进。
应用情况

总结
QUIC 丢掉了 TCP、TLS 的包袱,基于 UDP,并对 TCP、TLS、HTTP/2 的经验加以借鉴、改进,实现了一个安全高效可靠的 HTTP 通信协议。
凭借着零 RTT 建立连接、平滑的连接迁移、基本消除了队头阻塞、改进的拥塞控制和流量控制等优秀的特性,QUIC 在绝大多数场景下获得了比 HTTP/2 更好的效果,HTTP/3 未来可期。
后记
关于HTTP的内容基本上讲完了,谢谢阅读,如有纰漏请联系我加以改正。
最开心的当然是...


教师节收到HR小姐姐的礼物啦~