图解网络:HTTP篇
HTTP是什么
HTTP:超文本传输协议,是应用层的协议
超文本:超越了普通文本的文本
HTTP是两点之间传输超文本的约定和规范
HTTP常见的状态码有哪些
1xx:提示信息
100 continue
2xx: 服务器成功处理了客户端的请求
200 ok
204 not content 表示响应头没有body数据
3xx: 客户端请求的资源发生了变动,需要重定向
301 Move Permanently 永久重定向,请求的资源已经不存在了,需要用新的URL再次访问。
302 Found 临时重定向,暂时需要用另一个URL来访问
304 not modified 资源未修改,重定向已存在的缓存文件
4xx 客户端发送的报文有误
400 bad request 客户端请求的报文有错误
403 forbidden 服务器禁止访问资源
404 Not found 请求的资源在服务器上找不到
5xx 服务器处理时内部发生了错误
500 internal server error 服务器端发生了错误,并不知道是什么错误
501 not implemented 客户端请求的功能还不支持
502 bad gateway 服务器作为网关或者代理时返回的错误码,表示服务器本身工作正常,访问后端服务器发生了错误
503 service unavailable 表示服务器当前很忙,暂时无法响应客户端
HTTP常见的字段有哪些
**HOST:**客户端发送请求时,用来指定服务器的域名
请求可以发送给同一个服务器上的不同网站
**Content-Length:**本次响应的数据长度
补充:HTTP头部是以一行一行的形式组织的,每一行以回车符(\r)和换行符(\n)结尾,最后有一个空行表示头部结束,空行后面是HTTP消息的主体(body)
**Connection:**表示客户端要求服务器端使用[HTTP长连接]机制,以便其他请求复用。
HTTP长连接的特点:只要任意一端没有明确提出断开连接,则保持TCP连接状态。
HTTP1.1默认是长连接,但为了兼容老版本的HTTP,需要指定Connection 为Keep-Alive
**Content-Type:**告知本次数据的格式
Content-Type: text/html;Charset=utf-8
客户端用:Accept:*/*
表示可以接受任何格式的数据
Content-Encoding: 数据的压缩方法
Content-Encoding: gzip
客户端:Accept-Encoding: gzip, deflate
GET和POST有什么区别
- GET:获取指定资源,POST是根据请求负荷(报文 body)对指定的资源做出处理。
- get将请求的数据放到url上,用?分割url和传输数据,参数用&连接,不安全;post将数据放到body中。
- get提交的数据最大是2k( 限制实际上取决于浏览器), post理论上没有限制。
- GET产生一个TCP数据包,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); POST产生两个TCP数据包,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
- GET请求会被浏览器主动缓存,而POST不会,除非手动设置。
GET和POST方法都是安全和幂等的吗
安全:请求方法不会破环服务器上的资源
幂等指多次请求,得到相同的响应
GET是安全且幂等,所以可以对GET请求的数据做缓存,缓存到浏览器上,同时GET请求可以在浏览器中保存为书签
==补充:GET理论上可以带body,但GET不需要用到body==
POST不安全且不幂等
HTTP缓存有哪些实现方法
强制缓存和协商缓存
什么是强制缓存
定义:只要浏览器判断缓存没有过期,则直接使用浏览器本地的缓存。使用Response Header的两个字段来实现强制缓存
Cache-Control,是一个相对时间
Expires,是一个绝对时间,如果客户端与服务器的时间不同步,可能会导致缓存失效的不准确性。
所以Cache-Control的优先级高于Expires
流程:
- 浏览器首次请求服务器资源时,服务器返回资源同时设定Cache-Control的过期时间
- 再次请求该资源时,浏览器会检查过期时间,若未过期则使用缓存,否则重新请求服务器
- 服务器再次收到请求后,会再次更新Response头部的Cache-Control
什么是协商缓存
定义:与服务端协商后,通过协商结果判断是否使用本地缓存
响应码为:304 Not Modified
涉及的字段
请求头部:If-Modified-Since
,If-None-Match
响应头部:Last-Modified
,Etag
- 将Last-Modified的值赋给If-Modified-since
- 将Etag的值赋给If-None-Match
流程:
If-None-Match和Etag可以避免由于==时间篡改==导致的不可靠问题。
所以Etag优先级更高。
HTTP1.1的优点有哪些
- 简单
- 报文的格式为 header+body,头部信息为key-value,易于理解
- 灵活和易于扩展
- 请求方法、状态码、头字段等都允许开发人员自定义和扩充
- HTTP工作在应用层,其下层可以随意变化HTTPS是HTTP 和 TCP层之间增加了SSL/TLS安全传输层HTTP3.0传输协议改用UDP协议
HTTP1.1的缺点有哪些
- 无状态
- 好处:无需额外的资源来记录状态信息,减轻服务器的负担。
- 坏处:在有关联性的操作中,服务器每次都要验证用户信息。
- 解决方案:使用Cookie技术来维持客户端的状态信息。
- 明文传输
- 好处:方便调试和查看信息
- 坏处:在传输过程中信息容易被窃取
- 不安全
- 使用明文,容易被窃听和篡改,不验证通信方的身份,可能遭遇伪装,且无法验证报文的完整性。
- 解决:引入SSL/TLS层,使用HTTPS来解决
HTTP1.1的性能如何
- **长连接:**只要任意一端没有明确提出断开连接,则保持TCP连接状态。 超过一定时间没有任何数据交互,服务端就会主动断开这个连接。
- 管道网络传输:允许客户端在同一个TCP连接中发送多个请求,无需等待响应返回,从而减少整体响应时间。 服务器必须按照接收请求的顺序发送对这些管道化请求的响应。
- **队头阻塞:**如果服务端在处理某个请求时耗时较长,那么后续的请求的处理都会被阻塞住。 HTTP1.1管道解决了请求的对头阻塞,没有解决响应的队头阻塞。
补充:HTTP1.1管道化技术不是默认开启,而且浏览器基本都没有支持。
HTTP与HTTPS有哪些区别
1. HTTP是明文传输的超文本传输协议,存在安全风险。HTTPS通过在TCP和HTTP之间加入SSL/TLS安全协议,实现报文的加密传输,解决了HTTP的不安全问题。1. HTTPS的连接建立比HTTP复杂,需要进行SSL/TLS握手过程。1. HTTPS使用443端口,HTTP使用80端口。1. HTTPS需向CA申请数字证书以确保服务器身份可信。
HTTPS解决了HTTP的哪些问题
HTTP 以下三个风险:
- 窃听风险,比如通信链路上可以获取通信内容,用户号容易没。
- 篡改风险,比如强制植入垃圾广告。
- 冒充风险,比如冒充淘宝网站。
1. 混合加密的方式实现信息的机密性,解决了窃听风险。
- 混合加密:对称加密和非对称加密结合
- 在通信建立前采用非对称加密的方式交换「会话秘钥」
- 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
- 「混合加密」的方式的原因: 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换。非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。
- 摘要算法的方式来实现完整性,它能够为数据生成独一无二的「指纹」用于校验数据的完整性,解决了篡改风险。
- 为确保传输内容完整性,要计算出指纹(摘要),与内容一起传输。对方收到后计算出指纹,比较判断内容是否被篡改。
- 用摘要算法(哈希函数)来计算出内容的哈希值,也就是内容的「指纹」,这个哈希值是唯一的,且无法通过哈希值推导出内容。
- 通过哈希算法可以确保内容不会被篡改,但是并不能保证「内容 + 哈希值」不会被中间人替换,因为这里缺少对客户端收到的消息是否来源于服务端的证明。 非对称加密有两个主要用途: 保证内容传输的安全:使用公钥加密,私钥解密的方式,确保只有持有私钥的人才能解密传输的内容,从而保证内容的机密性和安全性。确认消息的身份:使用私钥加密,公钥解密的方式,实现数字签名,以确认消息的来源,防止消息被冒充。通常对内容的哈希值进行加密,而不是对实际内容进行加密。 私钥是由服务端保管,然后服务端会向客户端颁发对应的公钥。如果客户端收到的信息,能被公钥解密,就说明该消息是由服务器发送的。
- 将服务器公钥放入到数字证书中,解决了冒充风险。
- 数字证书是由CA颁发的一种电子证书,用于证明公钥的真实性和所有者的身份。
HTTPS是如何建立连接的
SSL/TLS 协议基本流程:
- 客户端向服务器索要并验证服务器的公钥。
- 双方协商生产「会话秘钥」。
- 双方采用「会话秘钥」进行加密通信。
SSL/TLS 1.2 需要 4 握手,需要 2 个 RTT 的时延。
SSL/TLS 1.3 优化了过程,只需要 1 个 RTT 往返时延,也就是只需要 3 次握手:
HTTPS RSA握手解析
1. ClientHello
- 客户端发送ClientHello消息,包含支持的TLS协议版本、随机数(Client Random)和支持的密码套件列表(如RSA加密算法)。
2. SeverHello+Server Certificate+Server Hello Done
- 服务器收到请求后,发送ServerHello消息,包含确认的TLS协议版本(如果浏览器不支持,则关闭加密通信)、随机数(Server Random)、从客户端的密码套件列表选择一个合适的密码套件和服务器的数字证书。密码套件:Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256基本的形式是「密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法」, 一般 WITH 单词前面有两个单词,第一个单词是约定密钥交换的算法,第二个单词是约定证书的验证算法。由于 WITH 单词只有一个 RSA,则说明握手时密钥交换算法和签名算法都是使用 RSA;握手后的通信使用 AES 对称算法,密钥长度 128 位,分组模式是 GCM;摘要算法 SHA256 用于消息认证和产生随机数;
- 服务端为了证明自己的身份,会发送「Server Certificate」给客户端,这个消息里含有数字证书。
- 服务端发了「Server Hello Done」消息,表示服务器hello完成。
3.客户端回应
- 客户端通过浏览器或者操作系统中的 CA 公钥确认服务器的数字证书真实性,并从证书中获取服务器的公钥,使用它加密报文,向服务器发送如下信息 一个随机数(pre-master key),该随机数会被服务器的RSA公钥加密,并通过**[Client Key Exchange]**消息传给服务端。生成完「会话密钥」(master secret)后,然后客户端发一个「Change Cipher Spec」,告诉服务端开始使用加密方式发送消息。客户端发送「Encrypted Handshake Message(Finishd)」消息,把之前所有发生的数据做个摘要,再用会话密钥(master secret)加密一下,用来供服务端校验。
「Change Cipher Spec」之前传输的 TLS 握手数据都是明文,之后都是对称密钥加密的密文
服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。
4. 服务器的最后回应
服务器也是同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。
接下来就用「会话密钥」加解密 HTTP 请求和响应了。
==补充:基于 RSA 算法的 HTTPS 存在「前向安全」的问题:如果服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。==
前向安全:即使长期私钥(密钥对)泄漏,过去的通信数据仍然保持安全。
因为ECDHE使用临时的、一次性的密钥对来协商会话密钥。ECDHE的临时密钥对是一次性的,它们不会被存储或持久化。因此,即使长期私钥被攻击者获取,过去的会话密钥仍然保持安全,不会受到影响。
- 客户端和服务端交换临时的ECDHE公钥。
- 使用各自的长期私钥和对方的临时公钥,计算出一个共享的临时密钥。
- 这个共享的临时密钥被用于生成会话密钥,用于加密和解密通信。
HTTPS ECDHE握手解析
DH算法
模数P,底数G
公钥
公钥
当P很大,即使知道A和G,也算不出来a
双方交换公钥A、B,可以算出K作为会话密钥
根据私钥生成方式,DH算法分为两种
- static DH算法(已废弃),因为只有客户端的公钥是变化的,黑客可以依据某些数据暴力解出服务器的私钥,进而解出会话私钥,之前截取的加密数据也会被破解,所以static DH算法不具备前向安全性。
- DHE算法,双方的私钥在每次通信时,都是随机、临时生成的。
ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,可以用更少的计算量(DHE算法需要进行^运算)计算出公钥,以及最终的会话密钥。
ECDHE 算法
- 双方事先确定好用哪种椭圆曲线,和曲线上的基点G
- 双方各自生成一个随机数作为私钥d,得到公钥Q=dG
- 交换公钥后,A计算点(x1,y1)=d1Q2,B计算点(x2, y2) = d2Q1。因为椭圆曲线上满足乘法交换律和结合律,所以d1Q2 = d1d2G=d2d1G=d2Q1,所以双方的x坐标的一样的,他们共享会话密钥。
因为在椭圆曲线上,由于y坐标的平方与x坐标的立方之间存在关系,所以根据x坐标就可以唯一确定一个点。双方的x坐标是相同的,所以它们的会话密钥也相同。
ECDHE握手过程
TLS False Start
- 在TLS第四次握手前,客户端已经发送了加密HTTP数据,ECDHE相比RDA握手过程省去了一个消息往返的时间。
客户端校验数字证书的流程是怎样的?
<img src="https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost4@main/%E7%BD%91%E7%BB%9C/https/%E8%AF%81%E4%B9%A6%E7%9A%84%E6%A0%A1%E9%AA%8C.png" alt="img" style="zoom: 50%;" />
CA 签发证书的过程
- 首先CA 会持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
- 然后CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
- 最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程
- 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
- 浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
- 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
证书信任链的问题
向 CA 申请的证书一般不是根证书签发的,而是由中间证书签发的。
客户端只信任根证书 GlobalSign Root CA 证书的,然后 “GlobalSign Root CA” 证书信任 “GlobalSign Organization Validation CA - SHA256 - G2” 证书,而 “GlobalSign Organization Validation CA - SHA256 - G2” 证书又信任 baidu.com 证书,于是客户端也信任 baidu.com 证书。
Root CA 为什么不直接颁发证书,而是要搞那么多中间层级呢?
为了确保根证书的绝对安全性,将根证书隔离地越严格越好,不然根证书如果失守了,那么整个信任链都会有问题。
HTTPS的应用数据是如何保证完整性的?
TLS 在实现上分为握手协议和记录协议两层:
- TLS 握手协议就是我们前面说的 TLS 四次握手的过程,负责协商加密算法和生成对称密钥,后续用此密钥来保护应用程序数据(即 HTTP 数据);
- TLS 记录协议负责保护应用程序数据并验证其完整性和来源,所以对 HTTP 数据加密是使用记录协议;
<img src="https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/HTTP/%E8%AE%B0%E5%BD%95%E5%8D%8F%E8%AE%AE.png" alt="img" style="zoom: 33%;" />
- 首先,消息被分割成多个较短的片段,然后分别对每个片段进行压缩。
- 接下来,经过压缩的片段会被加上消息认证码(MAC 值,这个是通过哈希算法生成的),这是为了保证完整性,并进行数据的认证。通过附加消息认证码的 MAC 值,可以识别出篡改。与此同时,为了防止重放攻击,在计算消息认证码时,还加上了片段的编码。
- 再接下来,经过压缩的片段再加上消息认证码会一起通过对称密码进行加密。
- 最后,上述经过加密的数据再加上由数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据。
记录协议完成后,最终的报文数据将传递到传输控制协议 (TCP) 层进行传输。
补充:重放攻击是一种网络安全攻击,攻击者在通信过程中窃取了合法的数据包,并在稍后的时间内重新发送这些数据包,以欺骗目标系统执行相同的操作或获得未经授权的访问权限。
攻击利用数据包的可重复性,使目标系统误以为这些重放的数据包是合法用户发送的,从而导致安全漏洞和数据泄露等问题。
为防止重放攻击,可采取添加时间戳、随机数、加密和数字签名等措施。
HTTPS一定安全可靠吗?
客户端通过浏览器向服务端发起 HTTPS 请求时,被「假基站」转发到了一个「中间人服务器」,于是客户端是和「中间人服务器」完成了 TLS 握手,然后这个「中间人服务器」再与真正的服务端完成 TLS 握手。
什么是中间人攻击
中间人攻击是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。
HTTPS 协议本身到目前为止还是没有任何漏洞的,即使你成功进行中间人攻击,本质上是利用了客户端的漏洞(用户点击继续访问或者被恶意导入伪造的根证书),并不是 HTTPS 不够安全。
为什么抓包工具能截取 HTTPS 数据?
中间人要拿到私钥只能通过如下方式:
- 去网站服务端拿到私钥;
- 去CA处拿域名签发私钥;
- 自己签发证书,切要被浏览器信任;
抓包工具只能使用第三种方式取得中间人的身份。
使用抓包工具进行 HTTPS 抓包的时候,需要在客户端安装 Fiddler 的根证书,这里实际上起认证中心(CA)的作用。
如何避免被中间人抓取数据?
通过 HTTPS 双向认证来避免这种问题。
一般我们的 HTTPS 是单向认证,客户端只会验证了服务端的身份,但是服务端并不会验证客户端的身份。
HTTP1.1相比HTTP1.0提高了什么性能
HTTP/1.1相比HTTP/1.0在性能上的改进包括:
- 使用长连接,减少短连接的性能开销。
- 支持管道传输,允许并行发送多个请求,减少整体响应时间。
但HTTP/1.1仍存在性能瓶颈:
- 未经压缩的请求/响应头部导致延迟增加。
- 冗长的首部信息造成资源浪费。
- 服务器按请求顺序响应,可能导致队头阻塞。
- 缺乏请求优先级控制。
- 请求只能由客户端开始,服务器被动响应。
HTTP/1.1如何优化
如何避免发送 HTTP 请求?
客户端会把第一次请求以及响应的数据保存在本地磁盘上,其中将请求的 URL 作为 key,而响应作为 value,两者形成映射关系。
- 强制缓存
- 协商缓存
如何减少 HTTP 请求次数?
减少重定向请求次数
将原本由客户端处理的重定向请求,交给代理服务器处理,这样可以减少重定向请求的次数;
合并请求
将多个小资源(图片)合并成一个大资源再传输,能够减少 HTTP 请求次数以及 头部的重复传输,再来减少 TCP 连接数量,进而省去 TCP 握手和慢启动的网络消耗。
将同一个页面的资源分散到不同域名,提升并发连接上限,因为浏览器通常对同一域名的 HTTP 连接最大只能是 6 个;将同一个页面的资源分散到不同域名,提升并发连接上限,因为浏览器通常对同一域名的 HTTP 连接最大只能是 6 个;
延迟发送请求
按需访问资源,只访问当前用户看得到/用得到的资源,当客户往下滑动,再访问接下来的资源,以此达到延迟请求,也就减少了同一时间的 HTTP 请求次数。
如何减少 HTTP 响应的数据大小?
无损压缩
适合用在文本文件、程序可执行文件、程序源代码。
- 把代码中的换行符或者空格去掉
- 对原始资源建立统计模型,利用这个统计模型,将常出现的数据用较短的二进制比特序列表示,将不常出现的数据用较长的二进制比特序列表示,生成二进制比特序列一般是「霍夫曼编码」算法。
- gzip 就是比较常见的无损压缩。
- gzip 的压缩效率相比 Google 推出的 Brotli (br)算法还是差点意思。
有损压缩
有损压缩主要将次要的数据舍弃,牺牲一些质量来减少数据量、提高压缩比,这种方法经常用于压缩多媒体数据,比如音频、视频、图片。
通过 HTTP 请求头部中的 Accept
字段里的「 q 质量因子」,告诉服务器期望的资源质量
Accept: audio/*; q=0.2, audio/basic
图片:WebP 格式
音视频:音视频数据通常是动态的,每个帧都有时序关系。然而,在某些情况下,时间连续的帧之间的变化是很小的,例如一个人在看书的视频中,只有手和书桌上的书在变化,其他地方保持静态。因此,可以利用这种特性,在一个静态的关键帧上使用增量数据来表达后续帧,从而减少数据量。
HTTP2做了哪些优化
HTTP2是基于HTTPS的
HTTP/2 相比 HTTP/1.1 性能上的改进:
- 头部压缩 同时发送多个请求,他们的头都是一样的或是相似的。HTTP/2采用HPACK算法(静态表、动态表、Huffman 编码)来压缩头部信息:客户端和服务器维护一张头信息表,通过索引号来避免重复发送相同的头部字段,从而提高数据传输速度。
- 二进制格式 HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧(Headers Frame)和数据帧(Data Frame)。 比如状态码 200 ,在 HTTP/1.1 是用 '2''0''0' 三个字符来表示(二进制:00110010 00110000 00110000),共用了 3 个字节。在 HTTP/2 对于状态码 200 的二进制编码是 10001000,只用了 1 字节就能表示,相比于 HTTP/1.1 节省了 2 个字节。
- 并发传输 HTTP/2引入了Stream概念,在一条TCP连接中复用多个Stream,实现了并发传输。每个Stream可以包含一个或多个Message,每个Message包含一条或多条Frame,Frame是HTTP/2的最小单位,以二进制压缩格式存放HTTP/1中的内容(头部和包体)。通过独一无二的Stream ID区分不同的HTTP请求,在接收端可以按顺序组装成完整的HTTP消息,从而实现了并行交错地发送请求和响应,解决了HTTP/1中队头阻塞的问题。同一 Stream 内部的帧必须是严格有序的同一个连接中的 Stream ID 是不能复用的,只能顺序递增。当 Stream ID 耗尽时,需要发一个控制帧 GOAWAY来关闭 TCP 连接。在 Nginx 中通过 http2_max_concurrent_Streams 配置来设置 Stream 的上限,默认是 128 个。HTTP/2 可以对每个 Stream 设置不同优先级,帧头中的「标志位」可以设置优先级,比如客户端访问 HTML/CSS 和图片资源时,希望服务器先传递 HTML/CSS,再传图片。
- 服务器主动推送资源 HTTP/2 服务端不再是被动地响应,可以主动向客户端发送消息。客户端和服务器双方都可以建立 Stream, 因为服务端可以主动推送资源给客户端。Stream ID 也是有区别的,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号。服务器在推送资源时,会通过 PUSH_PROMISE 帧传输 HTTP 头部,并通过帧中的 Promised Stream ID 字段告知客户端,接下来会在哪个偶数号 Stream 中发送包体。
在 HTTP/2 中,客户端在访问 HTML 时,服务器可以直接主动推送 CSS 文件,减少了消息传递的次数。
HTTP/2 有什么缺陷?
- 队头阻塞
HTTP/2解决了HTTP/1的队头阻塞问题,但在TCP层面仍然存在队头阻塞。
由于TCP是字节流协议,TCP层必须保证收到的字节数据是完整且连续的,当前一个字节数据没有到达时,后续的数据只能存放在内核缓冲区中,无法被HTTP/2应用层读取。
这种TCP层的队头阻塞是由于丢包触发TCP的重传机制,导致整个TCP连接中的所有HTTP请求都必须等待丢失的数据包被重传,影响了传输效率。
- TCP 与 TLS 的握手时延迟
TCP 三次握手和 TLS 四次握手,共有 3-RTT 的时延
- 网络迁移需要重新连接
移动设备从 4G 网络环境切换到 WiFi 时,由于 TCP 是基于四元组来确认一条 TCP 连接的,那么网络环境变化后,就会导致 IP 地址或端口变化,于是 TCP 只能断开连接,然后再重新建立连接,切换网络环境的成本高;
HTTP3做了哪些优化
- HTTP/1.1 中的管道( pipeline)虽然解决了请求的队头阻塞,但是没有解决响应的队头阻塞
- HTTP/2 虽然通过多个请求复用一个 TCP 连接解决了 HTTP 的队头阻塞 ,但是一旦发生丢包,就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞。
HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!
UDP 是一个简单、不可靠的传输协议,而且是 UDP 包之间是无序的,也没有依赖关系。而且,UDP 是不需要连接的,也就不需要握手和挥手的过程
UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。
QUIC 有以下 3 个特点。
- 无队头阻塞 QUIC 协议也有类似 HTTP/2 Stream 与多路复用的概念当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。
- 更快的连接建立 HTTP/1和HTTP/2先 TCP 握手,再 TLS 握手。(2RTT)HTTP/3使用QUIC协议内部包含TLS/1.3,可以在一个RTT(握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。)内完成连接和密钥协商,而且在会话恢复时可以实现0-RTT效果,大大减少了延迟。会话恢复:在客户端与服务器建立连接后,利用之前保存的连接信息和密钥,在新连接中快速恢复会话状态的过程。
- 连接迁移 QUIC协议通过连接ID来标记通信的两个端点,客户端和服务器可以各自选择一组ID来标记自己。因此,即使移动设备的网络变化导致IP地址变化,只要保留了上下文信息(如连接ID、TLS密钥等),就可以无缝地复用原连接,消除重连的成本,实现了连接迁移的功能,没有卡顿感。
QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议。
HPACK 的静态表只有 61 项,QPACK 的静态表扩大到 91 项。
在首次请求-响应后,双方会将未包含在静态表中的 Header 项更新各自的动态表,后续传输时仅用 1 个数字表示。
如果首次请求发生丢包,导致服务器无法建立动态表并正确解码后续请求的头部,就会发生请求解码的延迟和阻塞,直到丢失的数据包被重新传输,使得服务器能够正确地解码所有请求。
QUIC 会有两个特殊的单向流
- 一个叫 QPACK Encoder Stream,用于将一个字典(Key-Value)传递给对方,比如面对不属于静态表的 HTTP 请求头部,客户端可以通过这个 Stream 发送字典;
- 一个叫 QPACK Decoder Stream,用于响应对方,告诉它刚发的字典已经更新到自己的本地动态表了,后续就可以使用这个字典来编码了。
这两个特殊的单向流是用来同步双方的动态表,编码方收到解码方更新确认的通知后,才使用动态表编码 HTTP 头部。
既然有HTTP协议为什么还要有RPC?
RPC(Remote Procedure Call),又叫做远程过程调用。它本身并不是一个具体的协议,而是一种调用方式。像 gRPC 和 Thrift 这样的具体实现,才是协议,它们是实现了 RPC 调用的协议。
RPC允许一个计算机程序调用另一个计算机程序的过程或函数,就像调用本地函数一样。RPC隐藏了底层通信细节,使得在分布式系统中实现跨网络的远程调用变得更加简单。
虽然大部分 RPC 协议底层使用 TCP,但实际上它们不一定非得使用 TCP,改用 UDP 或者 HTTP,其实也可以做到类似的功能。
HTTP和RPC的区别
服务发现
- HTTP中的服务发现:通过DNS服务将域名解析为对应的IP地址,默认端口一般是80。DNS充当了服务发现的角色,帮助客户端找到正确的服务器。
- RPC中的服务发现:通常会使用专门的中间服务(如Consul、Etcd、Redis、CoreDNS等)来保存服务名与IP地址的映射关系。当客户端想要访问某个服务时,它会向这些中间服务查询相应的IP和端口信息,然后进行连接。
底层连接形式
HTTP/1.1和RPC协议都使用TCP长连接进行数据交互,但RPC协议通常会建立连接池,可以复用多条连接来提高性能,而HTTP/1.1默认也使用长连接但不会维护连接池。
传输的内容
将结构体转为二进制数组的过程就叫序列化,反过来将二进制数组复原成结构体的过程叫反序列化。
HTTP/1.1在报文中传输内容以字符串为主。Header和Body都采用字符串传输,导致报文冗余和啰嗦。即使在JSON结构体数据中也存在冗余的问题。
RPC具有更高的定制化程度,可以采用体积更小的Protobuf或其他序列化协议来保存结构体数据。
HTTP/2.0 在 HTTP/1.1 的基础上做了优化,性能可能比很多 RPC 协议都要好,但由于是这几年才出来的,所以也不太可能取代掉 RPC。
既然有HTTP协议,为什么还要有WebSocket?
对于登录页面这样的简单场景,可以使用定时轮询或者长轮询的方式实现服务器推送(comet)的效果。
不断轮询
不断定时发 HTTP 请求到服务器,服务器收到请求后给客户端响应消息。
最常见的就是扫码登录。
长轮询
如果我们的 HTTP 请求将超时设置的很大,比如 30 秒,在这 30 秒内只要服务器收到了扫码请求,就立马返回给客户端网页。如果超时,那就立马发起下一次请求。
WebSocket是什么
WebSocket是一种基于TCP的全双工通信协议,用于在客户端和服务器之间实现实时、双向的数据传输。
怎么建立WebSocket连接
- 浏览器与服务器进行TCP三次握手建立连接。
- 浏览器发送HTTP请求,包含特殊的头部信息表明要升级到WebSocket协议。Sec-WebSocket-Key是随机生成的 base64 码
- 服务器收到请求,验证是否支持WebSocket协议。如果支持,进行WebSocket握手流程,并将握手后的响应包含101状态码和Sec-WebSocket-Accept头部返回给浏览器。Sec-WebSocket-Accept是根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串。
- 浏览器也用同样的公开算法将base64码转成另一段字符串,如果这段字符串跟服务器传回来的字符串一致,那验证通过。
WebSocket的消息格式
WebSocket的数据格式也是数据头(内含payload长度) + payload data 的形式。
这是因为 TCP 协议本身就是全双工,但直接使用纯裸TCP去传输数据,会有粘包的"问题"。消息头里一般含有消息体的长度,通过这个长度可以去截取真正的消息体。
WebSocket的使用场景
适用于需要服务器和客户端(浏览器)频繁交互的大部分场景,比如网页/小程序游戏,网页聊天室,以及一些类似飞书这样的网页协同办公软件。
#计算机网络知识点汇总#本专栏是作者阅读小林coding的图解网络后的总结版,适合找工作直接背诵。