深入理解HTTP协议


1.基本概念

超文本传输协议,也就是HyperText Transfer Protocol。HTTP 是为 Web 浏览器与 Web 服务器之间的通信而设计的,但也可以用于其他目的。HTTP 是一个基于 TCP/IP 通信协议来传递数据。

特点:

  • 无连接的:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  • 媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。
  • HTTP协议是无状态协议。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

常见状态码:

  • 1xx:信息性状态码,接收的请求正在处理。
  • 2xx:成功状态码,200 OK(成功)服务器已成功处理了请求。204 Not Connent 请求处理成功,但是没有资源返回
  • 3xx:重定向状态码,301 MovedPermanently 资源永久移动。302 Found 资源临时移动
  • 4xx:客户端错误状态码,401 403 Forbidden。表明对请求资源的访问被服务器拒绝了。404 Not Found。表明服务器上找不到请求的资源。
  • 5xx:服务器错误状态码。500 Internal Server Error。表明服务器端在执行请求时发生了错误。504。Gateway Time-Out。指服务器作为网关或代理,但是没有及时从上游服务器收到请求。

请求报文由4部分组成:请求行,请求头部,空行,请求体。

  • 请求行包括:请求方法字段、URL字段、HTTP协议版本字段。它们用空格分隔。例如,GET /index.html HTTP/1.1。

  • 请求头部:请求头部由键/值对组成,每行一对,关键字和值用英文冒号“:”分隔

  • 请求体: post put等请求携带的数据

响应报文由4部分组成:响应行,响应头部,空行,响应体。

常见字段:

  • Host:服务器的域名,允许多个域名同处一个IP地址,即虚拟主机。
  • Content-Length:服务器在返回数据时,会有该字段,表明本次回应的数据长度。例如,Content-Length:1000,就是告诉浏览器,本次服务器回应的数据长度是 1000 个字节,后面的字节就属于下一个回应了。HTTP 是基于 TCP 传输协议进行通信的,而使用了 TCP 传输协议,就会存在一个“粘包”的问题,HTTP 协议通过设置回车符、换行符作为 HTTP header 的边界,通过 Content-Length 字段作为 HTTP body 的边界,这两个方式都是为了解决“粘包”的问题。
  • Connection:最常用于客户端要求服务器使用HTTP 长连接机制,以便其他请求复用。

HTTP 长连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

  • Content-Type:用于服务器回应时,告诉客户端,本次数据是什么格式。

  • Content-Encoding:说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式。

通信数据转发程序:代理、网关、隧道

代理:代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端“中间人”的角色,接收由客户端发送的请求并转发给服务器,同时也接收服务器返回的响应并转发给客户端。

网关:网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个网关。

隧道:隧道可按要求建立起一条与其他服务器通信的线路,届时使用SSL等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信。

隧道本身不会去解析HTTP请求。也就是说,请求保持原样中转给之后的服务器。隧道会在双方通信断开是结束。


2.GET和POST有什么区别?

GET请求

GET的语义是说从服务器获取指定的资源,这个资源可以是静态的文件,页面,图片,视频等。GET请求的参数位置一般是写在URL中的,URL规定只能支持ASCII,所以GET请求的参数只允许ASCII字符,而且浏览器对URL的长度是有限制的

POST请求

POST的语义是根据请求的负荷(报文body)对指定的资源做出处理,具体的处理方式视资源的类型而不同,POST请求携带的数据一般都是写在body中的,而且浏览器对body的大小不会做出限制

实际上Get也能带Body,只是规范中不提倡,同时Post请求的url中也能提交参数。


3.GET和POST都是幂等的吗?

安全:请求方法不会破坏浏览器上的资源

幂等:多次执行相同的操作,结果都是相同的

  • Get方法是安全而且幂等的,因为它是只读操作,无论操作多少次,都不会对服务器上的数据造成影响

基于GET请求的幂等性,因为它是只读的操作,无论操作多少次,服务器上的数据都是安全的,所以可以对GET请求做缓存,这个缓存既可以缓存到代理服务器上,也可以缓存到浏览器本身

  • POST因为是新增或者提交数据,因此是不安全的,同时也不一定是幂等的,因为提交数据可能导致服务器资源的改变,而且多次提交就会多次创建资源

为了避免数据被窃取,就要使用HTTPS协议


4.HTTP缓存的实现方式?

强制缓存和协商缓存

这两种缓存的对象都是那些每次请求都能得到一样的请求数据

强制缓存

强制缓存指的是浏览器只要判断缓存没有过期,就可以继续使用,是否使用缓存的决定权在于浏览器

比如说我在项目开发的时候,有一次偶然看到HTTP的状态码中标注from disk cache

强制缓存是利用下面这两个首部字段实现的,它们都用来表示资源在客户端缓存的有效期:

  • Cache-Control:表示的是相对过期时间
  • Expires:表示的是绝对过期时间

如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级高于 Expires 。

Cache-control 选项更多一些,设置更加精细,所以建议使用 Cache-Control 来实现强缓存。具体的实现流程如下:

  • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中的max-age参数指明了过期时间大小;
  • 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
  • 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。

协商缓存

协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存。第一次访问之后,客户端本地有了缓存,当第二次发起请求收到的响应报文的状态码为304,这个时候浏览器就可以使用本地缓存。

协商缓存可以基于两种头部来实现。

第一种:请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现,这两个字段的意思是:

  • 响应头部中的 Last-Modified:标示这个响应资源的最后修改时间;
  • 请求头部中的 If-Modified-Since:当资源过期了,发现响应头中具有 Last-Modified 声明,则再次发起请求的时候带上 Last-Modified 的时间,服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比(Last-Modified),如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。

第二种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段,这两个字段的意思是:

  • 响应头部中 Etag:唯一标识响应资源;
  • 请求头部中的 If-None-Match:当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。

第一种实现方式是基于时间实现的,第二种实现方式是基于一个唯一标识实现的,相对来说后者可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。

如果在第一次请求资源的时候,服务端返回的 HTTP 响应头部同时有 Etag 和 Last-Modified 字段,那么客户端再下一次请求的时候,如果带上了 ETag 和 Last-Modified 字段信息给服务端,这时 Etag 的优先级更高,也就是服务端先会判断 Etag 是否变化了,如果 Etag 有变化就不用在判断 Last-Modified 了,如果 Etag 没有变化,然后再看 Last-Modified。

为什么 ETag 的优先级更高?这是因为 ETag 主要能解决 Last-Modified 几个比较难以解决的问题:

  1. 在没有修改文件内容情况下文件的最后修改时间可能也会改变,这会导致客户端认为这文件被改动了,从而重新请求;
  2. 可能有些文件是在秒级以内修改的,If-Modified-Since 能检查到的粒度是秒级的,使用 Etag就能够保证这种需求下客户端在 1 秒内能刷新多次;
  3. 有些服务器不能精确获取文件的最后修改时间。

注意,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。


5.讲讲http缓存的实现原理

HTTP的缓存工作原理是基于强缓存+协商缓存的,这种实现能够尽可能的减少网络通信量。

首先,当浏览器要发出一个请求时,他会先检查字段,分别是Cache-Control,这个字段在缓存工作时设置为max-age=???,然后在通过比较当前的时间和请求头中的Date+max-age值的大小,如果小于了,直接走缓存,否则的话视为缓存不命中。

当缓存不命中的时候,开始请求服务器,首先它会发现响应头中有eTag,于是将eTag的值赋值给If-None-Match,如果这个If-None-Match在服务端找不到或者在服务端的资源能够对应上,这时候直接返回304,告诉浏览器走缓存,否则携带上这个eTag进行响应。

如果没有eTag这个字段,它会在响应头中找一个叫做Last-Modified的字段,然后通过赋值If-Modified-Since,发起新新的请求,服务端就检查这个资源的Last-Modified,然后这时候会有两种情况

  • 客户端的修改时间比服务端的修改时间要晚,因此直接走缓存,304
  • 客户端的修改时间比服务端的修改时间要早,因此重新发送数据,200

然后在返回新响应的时候,带上这个Last-Modified

还有一种情况是强缓存仅基于expire实现,它记录的是绝对时间,但是通常由于服务端时钟和客户端时钟不一致,而不使用,精度较低


6.HTTP/1.1了解过吗?说说优点和缺点?

HTTP的优点

  • 简单

HTTP报文段的格式就是head+Body,头部信息也是基于key-value实现的,因此简单

  • 灵活,容易扩展

HTTP协议中规定的URI和URL等组成部分并没有固定,允许开发人员自行定义和扩充,因此功能上比较容易扩充

其底层的实现是可插拔式的,而且用户无感知,或者增加TSL/SSL等安全认证机制

  • 跨平台:各种设备都能够使用HTTP协议进行网络的通信

HTTP/1.1无状态的双刃剑问题

HTTP协议是无状态的,无状态的好处是能够减少维护这次连接上的各种复杂的状态信息,减轻了CPU和内存的负担,使得这些资源更加专注于为用户提供服务

坏处则是其因为无法存储当前的状态信息,当需要完成一系列有关联性的操作的时候,需要添加附加信息

HTTP/1.1虽然是无状态协议,但是为了实现保持状态的功能引入了Cookie技术。响应报文中有一个Set-Cookie的首部字段,服务器在发送响应报文时往这个字段写入,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值再发出去。服务端发现客户端发送过来的Cookie后,会和服务器上的记录做对比,最后得知之前的状态信息。

HTTP/1.1明文传输的双刃剑问题

明文传输的好处是程序容易调试,仅仅使用浏览器就能够对请求的信息进行分析

但是坏处是导致用户的信息泄漏,在复杂的网络中进行传输的时候,会经过错综复杂的网络结构,一旦被别有用心之人截获,就会导致非常严重的后果,问题的解决具有一定成本,比如引入复杂的加密算法,如TSL/SSL等机制,保护用户的信息,这增加了双方的通信量以及协议的复杂程度,因为还需要对加密的数据进行编码和解码

HTTP/1.1最严重的问题就是不安全,然而这个问题可以通过SSL/TSL的方式进行解决

HTTP/1.1的长连接是什么原理?

在HTTP/1.1之前使用的是HTTP/1.0,在早期的1.0版本中,有一个非常严重的性能问题,就是它使用的是短连接,所谓短连接就是一次TCP的连接与释放对应一次HTTP的请求和响应,在高并发的情况下,会导致大量的TCP的三报文握手和四报文挥手,十分浪费,因为光是TCP报文的首部就要占20个字节,更不用说底层的IP头的加装额外消耗。

于是HTTP/1.1提出了长连接,这个机制使得连接可复用,只要任意一端没有明确提出提出断开连接,则保持TCP连接状态。在HTTP/1.1中所有的连接默认都是长连接。

管道网络传输是什么?

长连接使得管道网络传输成为了可能,所谓管道网络传输是说,原本的请求-响应模型是阻塞式的,比如说第一个请求发出了,必须要等到第一个响应回来才能发第二个请求

而管道网络传输规定:可以一次性发送多个请求出去,但是接收响应必须按照请求的顺序进行接收。

然而HTTP/1.1是没有默认开启这个功能的

管道网络传输会带来什么问题?

这个问题叫做队头阻塞问题,严重时可能导致请求大量丢失和服务宕机

这个问题是这样发生,当第一个请求发送出去之后,由于I/O或者其他原因很长时间都没有收到响应,但是这时候后面的请求又都在排队,从而导致后面的请求无法得到响应,客户端陷入阻塞状态

这种会大大降低吞吐量,比如说请求2的完成只需要1ms,而请求1需要10s,等待的时间远远大于执行任务的时间。


7.HTTPS与HTTP有什么区别?

这个问题我认为可以从连接的建立过程、传输的信息安全性、默认端口、通信基础来回答

  • HTTP的建立是依托于TCP连接的,因此在连接建立的过程只需要完成三次握手即可,而HTTPS因为在HTTP和TCP之间引入了SSL/TSL协议,因此在完成三次握手之后,还需要完成SSL/TSL握手
  • HTTP的报文传输是明文传输的,而HTTPS的报文传输是经过加密之后的
  • HTTP的默认端口是80,HTTPS的默认端口是443
  • HTTPS在通信的时候需要有对应的CA来证明服务器是可信的

8.HTTPS解决了HTTP的哪些问题?

首先我们来看看HTTP存在的安全问题:

  • 数据被窃听的风险:通信使用明文(不加密),内容有可能被窃听。
  • 数据被篡改的风险:无法证明报文的完整性,有可能已经被篡改
  • 冒充的风险:不验证通信方的身份,因此有可能遭遇伪装

那么HTTPS引入了TSL/SSL就是为了解决这些问题

  • 信息加密手段:交互信息在没有密钥的情况下无法解密
  • 校验机制:通过杂凑函数等手段,校验数据是否被篡改过,篡改过则直接丢弃数据报
  • 身份机制:通过CA机构颁发的证书证明服务器是可信的

9.HTTPS是如何建立的?

由于引入了TLS/SSL算法,因此在TCP的三报文握手之后,还要执行身份验证等操作

  • 客户端向服务器索要公钥并且验证公钥的身份
  • 双方协商生产共享密钥
  • 之后都使用共享密钥进行数据的传输

TLS的握手过程包含了四次通信过程

  • ClientHello:客户端向服务器发起加密通信请求

(1) 客户端支持的TLS版本号

(2) 客户端支持生产的随机数,后面用于生成会话密钥的条件之一

(3) 客户端支持的密码套件,如RSA加密算法

  • ServerHello

(1) 确定TLS版本号

(2) 服务器生产的随机数,生产会话密钥的条件

(3) 确认的密码套件

(4) 服务器的数字证书

  • 客户端回应

客户端收到数字证书后,通过浏览器等软件提供的CA公钥,确认服务器的数字证书的真实性

如果数字证书没有问题,就从中取出公钥,然后用其加密报文

(1) 一个随机数,这个随机数通过公钥进行加密

(2) 加密算法改变通知,之后都用共享密钥进行通信

(3) 客户端握手结束通知,表示客户端的握手阶段已经结束了,同时将之前的所有内容的发生数据做个摘要,用来给服务端进行验证

此时,一共生产了三个随机数,然后通过这三个随机数,其中第三个随机数是通过公钥加密的,最终生产出了共享密钥

  • 服务器的最后响应

(1) 加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。

(2) 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。

至此,整个 TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。


10.HTTPS一定安全可靠吗?

这个问题实际上考察的是中间人攻击的问题

首先我们在之前,已经讨论到了数字证书的问题了,但是这个数字证书只要具有一定的资质就可以申请。

于是,如果中间人具有一份合法的数字证书,或者说它窃取了别人的数字证书,那么它也可以发起攻击

攻击的具体原因,首先客户端会向服务器发起请求,但是被一个假基站转发到了一个中间人服务器,然而这个中间人服务器使用了一份别人的数字证书,而这份数字证书是有效的,于是客户端完成了4次TLS握手,然后建立起通信,在这个过程中,中间人服务器同时向真正的服务器发起通信。

那么这样就很微妙了,中间人可以解开所有的数据,甚至能够篡改有关的数据,这样的话就会导致数据泄漏。

中间人服务器与客户端在 TLS 握手过程中,实际上发送了自己伪造的证书给浏览器,而这个伪造的证书是能被浏览器(客户端)识别出是非法的,于是就会提醒用户该证书存在问题。

如果用户执意点击「继续浏览此网站」,相当于用户接受了中间人伪造的证书,那么后续整个 HTTPS 通信都能被中间人监听了。

所以,这其实并不能说 HTTPS 不够安全,毕竟浏览器都已经提示证书有问题了,如果用户坚决要访问,那不能怪 HTTPS ,得怪自己手贱。

另外,如果你的电脑中毒了,被恶意导入了中间人的根证书,那么在验证中间人的证书的时候,由于你操作系统信任了中间人的根证书,那么等同于中间人的证书是合法的,这种情况下,浏览器是不会弹出证书存在问题的风险提醒的。

这其实也不关 HTTPS 的事情,是你电脑中毒了才导致 HTTPS 数据被中间人劫持的。

所以,HTTPS 协议本身到目前为止还是没有任何漏洞的,即使你成功进行中间人攻击,本质上是利用了客户端漏洞(用户点击继续访问或者被恶意导入伪造的根证书),并不是 HTTPS 不够安全。


11.CA机构是如何颁发数字证书的?

首先,服务器的运营人员向CA机构提出公开秘钥的申请,CA机构在检查了申请者的身份之后,会对已申请的公开秘钥做数字签名,然后分配这个已签名的公开秘钥,CA机构将个人信息+公钥+数字签名打包成一个数字证书。

服务器会将这份数字证书发给客户端,来进行公开秘钥加密通信。

接到数字证书的客户端使用CA机构的公钥对证书上的数字签名做验证,一旦验证通过,客户端便可以确定两件事,一是给这个服务器做认证的机构是真实有效的,二是该服务器的公钥是值得信赖的。

客户端上的CA机构的公钥是怎么来的呢?为了确保安全的转交,多数浏览器开发商发布版本时,会事先在内部植入常用认证机构的公钥。


12.HTTP/1.1 相比 HTTP/1.0 提高了什么性能?

这个问题我打算从HTTP/1.0和HTTP/1.1的区别进行描述

首先HTTP/1.0的最重要的特征就是短连接,也就是一次请求与响应就对应一次TCP的连接与释放

因此在大量请求到来的时候,性能就会严重下降。

于是HTTP/1.1引入了长连接,这种机制就是说,只要请求的收发双方没有一方明确提出要断开连接,那么底层就会保留这条TCP连接,减少了TCP连接的三报文握手和四报文挥手的巨大开销

同时,由于多个请求-响应复用同一条TCP连接,这使得管道网络传输成为可能,也就是说,这时候客户端发送请求时,不必等待前一个请求的响应到达即可发送请求。

但是同时HTTP/1.1具有相当一部分缺点

  • data的header没有做压缩,而只能对body做压缩,因此当header的体积过大时,将导致网络I/O传输性能下降
  • 将导致队头阻塞问题,虽然使用管道网络传输能够异步发送请求,但是接收响应却是同步的,在这种情况下,如果前面的响应没有发回来,然后后面的请求将一直无法接收到响应
  • 没有提供解决队头阻塞的优先级机制
  • 冗长的首部将导致传输浪费
  • 请求只能从客户端开始,服务器只能够被动响应,服务端无法主动推送服务

13.HTTP/2 做了什么优化?

关于这个问题,我想应该要从两个方面进行回答,第一个方面是安全方面

HTTP/2引入了TLS1.2+,也就是基于HTTPS的机制,使得HTTP/2的传输变得更加安全了

第二个方面是性能方面,性能方面做了较大的改动:

首先我们先来看看HTTP/1.1中各个痛点

  • HTTP/1.1的数据传输低效

它的传输低效主要存在于两点,第一,它的头部没有经过压缩,如果发送的请求/响应的头部冗长,而每次都发送这些请求的话,导致导致大量冗余信息在网络中传输

对于这个痛点,HTTP/2提供的解决方案是,客户端和服务端双方维护一张头信息表,这张表在初始化就被静态写入一些常用的头部字段,当需要使用到这些头部字段(以key-value的形式存储)的时候,就在数据包的头部中封装一个字段header:1 xxxx,其中1代表着这个头部字段在头信息表存在,xxx代表的是索引号,当第一个字段为0的时候,代表不存在,然后后边的这些xxx就是实际上的头部字段,然后传输到对等端的时候,会将这个字段记录到动态表中,方便下次使用

第二个低效的原因在于频繁的编码操作,HTTP/1.1的数据传输是基于文本传输的,而计算机硬件无法读取纯文本格式,只能够读取二进制的数据,在接收数据的时候,还需要将文本格式的数据解析为二进制的数据。

这就带来了严重的空间浪费了,比如说要传输的是200

  • 在HTTP/1.1中的形式是”2””0””0”,然后以二进制编码的方式就是三个字节
  • 然而在HTTP/2中由于全面采用了二进制编码格式,因此200就表示为1100 1000,节省了两个字节

全面采用了二进制,节省了传输所需要的编码量

  • 存在队头阻塞问题

这个队头阻塞问题指的是当响应迟迟没有到来的时候,后续的请求就无法得到响应

那么它是怎么解决的呢?

它引入了Stream流的概念,我们首先来理解为什么存在队头阻塞现象,这是因为如果不按请求顺序进行响应,就有可能将A的响应给到B,将B的响应给A,造成错乱

那么我们为什么不给这响应包加上一个控制字段,让这些包能够标识出来谁是谁的响应呢?

这就是Stream机制提出的一个核心思路,它在同一个TCP连接中存在多个Strteam,这多个Stream就代表着同一个请求-响应,他们通过在标识StreamId对这些Stream进行标识,从而确保对应的请求能够收到对应的请求

如果是这样的话,我们假设响应是乱序返回的,比如请求1、请求2发送,然后响应2、响应1返回,因为存在StreamId,接收方就能够通过不同Id标识拿到自己想要的数据包

通过Stream流的并发传输,提高了性能

  • 只能是客户端主动请求响应,而无法服务器主动推送

假设客户端向服务器等待服务器的长IO操作,只要等待它的长IO操作完成后才能返回响应,那么在这期间只能干等着,如果服务端能够主动推送响应,那么可以这样操作:

等服务器接收到客户端的请求,先临时告知客户端服务器正在操作,然后客户端就可以干自己的事情去了

然后当服务器做完自己的事情了,再向客户端推送,这样的话就可以提供用户的使用体验

HTTP/2有什么缺陷

它同样存在队头阻塞的问题,只不过它的队头阻塞问题是因为滑动窗口的限制而产生的,也就是队头阻塞产生在TCP层面,先来讲讲它是怎么产生的

我们假设发送双方维护了一个窗口,然后A同时发送了P1/P2/P3/p4/p5然后等待ACK,然后B能够接收P1/P2

P1,但是P2丢掉了,于是它只能够等待P2的超时重传,那么这期间,如果A再发送P3/P4/P5,都不能够再次接收

当考虑每个包大小一样的话,此时B应该能接收到P2/P3,但是后续的P4/P5均会被阻塞发送,即使到了也会被丢弃,因此此时P4/P5的响应就被搁置了,变成了队头阻塞


14.HTTP/3 做了哪些优化?

既然谈到了优化,那么肯定就是解决HTTP/2所没有解决的问题,HTTP/2没有解决TCP层面的队头阻塞问题

但是这个问题是致命的,因为发送窗口和接收窗口不可能无限制大小,而且为了可靠传输,必须保证数据包的有序接收,因此一个思路就是,修改底层的实现,改为UDP实现

首先要解决的问题是:之前提供的HTTP协议都是TCP的可靠传输,那么我们必须基于UDP实现可靠传输

核心就是上图中的QUIC协议

QUIC协议也有类似的HTTP/2中的Stream的机制,也就是说一条连接中有也有多个Stream,但是每一个Stream并不公用一个窗口,而是有各自的滑动窗口,因此如果流中的包丢失了,只会导致这个请求-响应被阻塞,其他的不被阻塞,这就解决了队头问题

与此同时,QUIC协议还基于UDP协议提高了性能

更快的连接建立

对比与HTTP/1.0、HTTP/1.1的实现,由于TCP+TLS的实现基于内核的TCP传输层和openssl库实现的,因此难以解耦,而QUIC的思路是:在完成连接握手的时候,在帧的首部携带上TLS认证信息,这个过程主要是为了确认双方的连接ID

甚至,在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。

连接的迁移

那么当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立连接。而建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,给用户的感觉就是网络突然卡顿了一下,因此连接的迁移成本是很高的。

而 QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID 来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。

所以, QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议。

QUIC 是新协议,对于很多网络设备,根本不知道什么是 QUIC,只会当做 UDP,这样会出现新的问题,因为有的网络设备是会丢掉 UDP 包的,而 QUIC 是基于 UDP 实现的,那么如果网络设备无法识别这个是 QUIC 包,那么就会当作 UDP包,然后被丢弃。


15.一台服务器怎么搭建多个web站点?

HTTP/1.1规范允许一台服务器搭建多个web站点。比如我们可以在阿里云申请一个域名,搭建网站。其使用的就是虚拟主机(虚拟服务器)功能。在互联网上,域名通过DNS服务器解析成IP地址,之后访问目标网站。可见,当请求发送到服务器时,已经是以IP地址销售访问了。

那么有着多个域名的服务器怎么知道这个请求是要去哪个域名呢?

在发送HTTP请求时,必须在首部的Host字段完整指定主机名或域名的URI。


文章作者: Fuchanglai
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Fuchanglai !
赏
  目录