You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
使用 session ID 的方式,每一次的会话都有一个编号,当对话中断后,下一次重新连接时,只要客户端给出这个编号,服务器如果有这个编号的记录,那么双方就可以继续使用以前的秘钥,而不用重新生成一把。目前所有的浏览器都支持这一种方法。但是这种方法有一个缺点是,session ID 只能够存在一台服务器上,如果我们的请求通过负载平衡被转移到了其他的服务器上,那么就无法恢复对话。
另一种是 DNS 的方式,DNS 可以用于在冗余的服务器上实现负载平衡。因为现在一般的大型网站使用多台服务器提供服务,因此一个域名可能会对应多个服务器地址。当用户向网站域名请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。这种方式有一个缺点就是,由于 DNS 服务器中存在缓存,所以有可能一个服务器出现故障后,域名解析仍然返回的是那个 IP 地址,就会造成访问的问题。
前言
这次梳理的篇幅主要是涉及网络部分,包括HTTP等,对巩固自己的网络知识体系也是很有帮助的,进一步的对性能优化而言也是帮助很大的。
但更多的是抛砖引玉,希望对你们有所帮助。
接下来就以问题的形式展开梳理👇
谈一谈HTTP协议优缺点
超文本传输协议,HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
HTTP 特点
HTTP 缺点
HTTP/1.0 HTTP1.1 HTTP2.0版本之间的差异
HTTP 0.9
HTTP 1.0
HTTP 1.1
http1.1是目前最为主流的http协议版本,从1999年发布至今,仍是主流的http协议版本。
keep-alive
来设置请求,进一步改进了HTTP协议的效率。
Range
来实现。http1.x版本问题
HTTP 2.0
二进制分帧
这是一次彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧":头信息帧和数据帧。头部压缩
HTTP 1.1版本会出现 User-Agent、Cookie、Accept、Server、Range 等字段可能会占用几百甚至几千字节,而 Body 却经常只有几十字节,所以导致头部偏重。HTTP 2.0 使用HPACK
算法进行压缩。多路复用
复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,且不用按顺序一一对应,这样子解决了队头阻塞的问题。服务器推送
允许服务器未经请求,主动向客户端发送资源,即服务器推送。请求优先级
可以设置数据帧的优先级,让服务端先处理重要资源,优化用户体验。谈一谈你对HTTP/2理解
头部压缩
HTTP 1.1版本会出现 User-Agent、Cookie、Accept、Server、Range 等字段可能会占用几百甚至几千字节,而 Body 却经常只有几十字节,所以导致头部偏重。
HTTP 2.0 使用
HPACK
算法进行压缩。那我们看看
HPACK
算法吧👇这种传索引的方式,可以说让请求头字段得到极大程度的精简和复用。
其次是对于整数和字符串进行哈夫曼编码,哈夫曼编码的原理就是先将所有出现的字符建立一张索引表,然后让出现次数多的字符对应的索引尽可能短,传输的时候也是传输这样的索引序列,可以达到非常高的压缩率。
多路复用
HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8个的TCP链接请求限制。
HTTP2中:
Stream ID
,流标识符,有了它,接收方就能从乱序的二进制帧中选择ID相同的帧,按照顺序组装成请求/响应报文。服务器推送
浏览器发送一个请求,服务器主动向浏览器推送与这个请求相关的资源,这样浏览器就不用发起后续请求。
相比较http/1.1的优势👇
二进制分帧
之前是明文传输,不方便计算机解析,对于回车换行符来说到底是内容还是分隔符,都需要内部状态机去识别,这样子效率低,HTTP/2采用二进制格式,全部传输01串,便于机器解码。
这样子一个报文格式就被拆分为一个个二进制帧,用Headers帧存放头部字段,Data帧存放请求体数据。这样子的话,就是一堆乱序的二进制帧,它们不存在先后关系,因此不需要排队等待,解决了HTTP队头阻塞问题。
在客户端与服务器之间,双方都可以互相发送二进制帧,这样子双向传输的序列,称为
流
,所以HTTP/2中以流来表示一个TCP连接上进行多个数据帧的通信,这就是多路复用概念。那乱序的二进制帧,是如何组装成对于的报文呢?
优先级
和流量控制
等功能,这样子的话,就可以设置数据帧的优先级,让服务器处理重要资源,优化用户体验。介绍一下HTTP 常见状态码
RFC 规定 HTTP 的状态码为三位数,第一个数字定义了响应的类别,被分为五类:
1xx 信息类
接受的请求正在处理,信息类状态码。
2xx 成功
响应报文中包含由 Content-Range 指定范围的实体内容。
3xx 重定向
4XX 客户端错误
5XX 服务器错误
DNS如何工作的
DNS 协议提供的是一种主机名到 IP 地址的转换服务,就是我们常说的域名系统。是应用层协议,通常该协议运行在UDP协议之上,使用的是53端口号。
我们通过一张图来看看它的查询过程吧👇
这张图很生动的展示了DNS在本地DNS服务器是如何查询的,一般向本地DNS服务器发送请求是递归查询的
本地 DNS 服务器向其他域名服务器请求的过程是迭代查询的过程👇
递归查询和迭代查询
递归查询指的是查询请求发出后,域名服务器代为向下一级域名服务器发出请求,最后向用户返回查询的最终结果。使用递归 查询,用户只需要发出一次查询请求。
迭代查询指的是查询请求后,域名服务器返回单次查询的结果。下一级的查询由用户自己请求。使用迭代查询,用户需要发出 多次的查询请求。
所以一般而言,本地服务器查询是递归查询,而本地 DNS 服务器向其他域名服务器请求的过程是迭代查询的过程。
DNS缓存
缓存也很好理解,在一个请求中,当某个DNS服务器收到一个DNS回答后,它能够回答中的信息缓存在本地存储器中。返回的资源记录中的 TTL 代表了该条记录的缓存的时间。
DNS实现负载平衡
它是如何实现负载均衡的呢?首先我们得清楚DNS 是可以用于在冗余的服务器上实现负载平衡。
**原因:**这是因为一般的大型网站使用多台服务器提供服务,因此一个域名可能会对应 多个服务器地址。
举个例子来说👇
总结
—>>
本地hosts文件—>>
本地DNS解析器—>>
本地DNS服务器—>>
其他域名服务器请求。 接下来的过程就是迭代过程。DNS 为什么使用 UDP 协议作为传输层协议?
DNS 使用 UDP 协议作为传输层协议的主要原因是为了避免使用 TCP 协议时造成的连接时延。
介绍一下Connection:keep-alive
什么是keep-alive
我们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器都要新建一个连接,完成 之后立即断开连接(HTTP协议为无连接的协议);
当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服 务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。
为什么要使用keep-alive
keep-alive技术的创建目的,能在多次HTTP之前重用同一个TCP连接,从而减少创建/关闭多个 TCP 连接的开销(包括响应时间、CPU 资源、减少拥堵等),参考如下示意图(来源:维基百科):
客户端如何开启
在HTTP/1.0协议中,默认是关闭的,需要在http头加入"Connection: Keep-Alive”,才能启用Keep-Alive;
http 1.1中默认启用Keep-Alive,如果加入"Connection: close “,才关闭。
目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求了,所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况。
介绍HTTP 缓存策略
这个跟之前的浏览器缓存原理一样,我直接拿我之前梳理过的吧。
我在我之前的那一篇中已经详细的说过了,点这里传送门聊一聊浏览器缓存
我们来梳理一下吧👇
强缓存
强缓存两个相关字段,Expires,Cache-Control。
强缓存分为两种情况,一种是发送HTTP请求,一种不需要发送。
首先检查强缓存,这个阶段**不需要发送HTTP请求。**通过查找不同的字段来进行,不同的HTTP版本所以不同。
Expires
Expires
即过期时间,时间是相对于服务器的时间而言的,存在于服务端返回的响应头中,在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求。比如下面这样:表示该资源在2020年
7月29日11:10:23
过期,过期时就会重新向服务器发起请求。这个方式有一个问题:服务器的时间和浏览器的时间可能并不一致,所以HTTP1.1提出新的字段代替它。
Cache-Control
HTTP1.1版本中,使用的就是该字段,这个字段采用的时间是过期时长,对应的是max-age。
上面代表该资源返回后6000秒,可以直接使用缓存。
当然了,它还有其他很多关键的指令,梳理了几个重要的👇
注意点:
协商缓存
强缓存失效后,浏览器在请求头中携带响应的
缓存Tag
来向服务器发送请求,服务器根据对应的tag,来决定是否使用缓存。缓存分为两种,Last-Modified 和 ETag。两者各有优势,并不存在谁对谁有
绝对的优势
,与上面所讲的强缓存两个Tag所不同。Last-Modified
这个字段表示的是最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。
浏览器接收到后,如果再次请求,会在请求头中携带
If-Modified-Since
字段,这个字段的值也就是服务器传来的最后修改时间。服务器拿到请求头中的
If-Modified-Since
的字段后,其实会和这个服务器中该资源的最后修改时间
对比:ETag
ETag是服务器根据当前文件的内容,对文件生成唯一的标识,比如MD5算法,只要里面的内容有改动,这个值就会修改,服务器通过把响应头把该字段给浏览器。
浏览器接受到ETag值,会在下次请求的时候,将这个值作为If-None-Match这个字段的内容,发给服务器。
服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对👇
两者对比
Last-Modified
优于ETag
,Last-Modified
记录的是时间点,而Etag
需要根据文件的MD5算法生成对应的hash值。ETag
优于Last-Modified
。ETag
按照内容给资源带上标识,能准确感知资源变化,Last-Modified
在某些场景并不能准确感知变化,比如👇最后,如果两种方式都支持的话,服务器会优先考虑
ETag
。缓存位置
接下来我们考虑使用缓存的话,缓存的位置在哪里呢?
浏览器缓存的位置的话,可以分为四种,优先级从高到低排列分别👇
Service Worker
这个应用场景比如PWA,它借鉴了Web Worker思路,由于它脱离了浏览器的窗体,因此无法直接访问DOM。它能完成的功能比如:
离线缓存
、消息推送
和网络代理
,其中离线缓存
就是Service Worker Cache。Memory Cache
指的是内存缓存,从效率上讲它是最快的,从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了。
Disk Cache
存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,优势在于存储容量和存储时长。
Disk Cache VS Memory Cache
两者对比,主要的策略👇
内容使用率高的话,文件优先进入磁盘
比较大的JS,CSS文件会直接放入磁盘,反之放入内存。
Push Cache
推送缓存,这算是浏览器中最后一道防线吧,它是
HTTP/2
的内容。具体我也不是很清楚,有兴趣的可以去了解。总结
Cache-Control
, 尝鲜,看强缓存是否可用If-Modified-Since
或者If-None-Match
字段检查资源是否更新说一说HTTP 的请求方法?
http/1.1
规定了以下请求方法(注意,都是大写):谈一谈GET 和 POST 的区别
本质上,只是语义上的区别,GET 用于获取资源,POST 用于提交资源。
想装逼请参考 https://zhuanlan.zhihu.com/p/22536382
具体差别👇
从应用场景角度来看,Get 多用于无副作用,幂等的场景,例如搜索关键字。Post 多用于副作用,不幂等的场景,例如注册。
options 方法有什么用?
OPTIONS 请求与 HEAD 类似,一般也是用于客户端查看服务器的性能。
这个方法会请求服务器返回该资源所支持的所有 HTTP 请求方法,该方法会用'*'来代替资源名称,向服务器发送 OPTIONS 请求,可以测试服务器功能是否正常。
JS 的 XMLHttpRequest对象进行 CORS 跨域资源共享时,对于复杂请求,就是使用 OPTIONS 方法发送嗅探请求,以判断是否有对指定资源的访问权限。
谈一谈你对URL理解
统一资源定位符的简称,Uniform Resource Locator,常常被称为网址,是因特网上标准的资源地址。
组成
通用的格式:scheme://host[:port]/path/…/?query#anchor
举个例子👇
这个URL中,https就是协议,www.baidu.com就是域名,默认端口是443,/s就是请求的path,
tn=baidu&bar=&wd=TianTian
这个就是queryURL 编码
举个例子👇
天天
转换为有效的ASCII格式就是%CC%EC%CC%EC
谈一谈队头阻塞问题
什么是队头阻塞?
对于每一个HTTP请求而言,这些任务是会被放入一个任务队列中串行执行的,一旦队首任务请求太慢时,就会阻塞后面的请求处理,这就是
HTTP队头阻塞
问题。有什么解决办法吗👇
并发连接
我们知道对于一个域名而言,是允许分配多个长连接的,那么可以理解成增加了任务队列,也就是说不会导致一个任务阻塞了该任务队列的其他任务,在
RFC规范
中规定客户端最多并发2个连接,不过实际情况就是要比这个还要多,举个例子,Chrome中是6个。域名分片
顾名思义,我们可以在一个域名下分出多个二级域名出来,而它们最终指向的还是同一个服务器,这样子的话就可以并发处理的任务队列更多,也更好的解决了队头阻塞的问题。
举个例子,比如
TianTian.com
,可以分出很多二级域名,比如Day1.TianTian.com
,Day2.TianTian.com
,Day3.TianTian.com
,这样子就可以有效解决队头阻塞问题。谈一谈HTTP数据传输
大概遇到的情况就分为定长数据 与 不定长数据的处理吧。
定长数据
对于定长的数据包而言,发送端在发送数据的过程中,需要设置
Content-Length
,来指明发送数据的长度。当然了如果采用了Gzip压缩的话,Content-Length设置的就是压缩后的传输长度。
我们还需要知道的是👇
Content-Length
,若是非Keep-alive,跟前面情况一样,Content-Length可有可无。那怎么来设置
Content-Length
举个例子来看看👇
不定长数据
现在采用最多的就是HTTP/1.1版本,来完成传输数据,在保存Keep-alive状态下,当数据是不定长的时候,我们需要设置新的头部字段👇
通过chunked机制,可以完成对不定长数据的处理,当然了,你需要知道的是
Transfer-Encoding
,优先采用Transfer-Encoding里面的方法来找到对应的长度。那我们来模拟一下吧👇
上面使用的是nodejs中http模块,有兴趣的小伙伴可以去试一试,以上就是HTTP对定长数据和不定长数据传输过程中的处理手段。
介绍一下HTTPS和HTTP区别
HTTPS 要比 HTTPS 多了 secure 安全性这个概念,实际上, HTTPS 并不是一个新的应用层协议,它其实就是 HTTP + TLS/SSL 协议组合而成,而安全性的保证正是 SSL/TLS 所做的工作。
SSL
安全套接层(Secure Sockets Layer)
TLS
(传输层安全,Transport Layer Security)
现在主流的版本是 TLS/1.2, 之前的 TLS1.0、TLS1.1 都被认为是不安全的,在不久的将来会被完全淘汰。
HTTPS 就是身披了一层 SSL 的 HTTP。
那么区别有哪些呢👇
我觉得记住以下两点HTTPS主要作用就行👇
介绍一个HTTPS工作原理
上一节来看,我们可以把HTTPS理解成HTTPS = HTTP + SSL/TLS
对称加密
加密和解密用同一个秘钥的加密方式叫做对称加密。Client客户端和Server端共用一套密钥,这样子的加密过程似乎很让人理解,但是随之会产生一些问题。
问题一: WWW万维网有许许多多的客户端,不可能都用秘钥A进行信息加密,这样子很不合理,所以解决办法就是使用一个客户端使用一个密钥进行加密。
问题二:既然不同的客户端使用不同的密钥,那么对称加密的密钥如何传输? 那么解决的办法只能是一端生成一个秘钥,然后通过HTTP传输给另一端,那么这样子又会产生新的问题。
问题三: 这个传输密钥的过程,又如何保证加密?如果被中间人拦截,密钥也会被获取, 那么你会说对密钥再进行加密,那又怎么保存对密钥加密的过程,是加密的过程?
到这里,我们似乎想明白了,使用对称加密的方式,行不通,所以我们需要采用非对称加密👇
非对称加密
通过上面的分析,对称加密的方式行不通,那么我们来梳理一下非对称加密。采用的算法是RSA,所以在一些文章中也会看见传统RSA握手,基于现在TLS主流版本是1.2,所以接下来梳理的是TLS/1.2握手过程。
非对称加密中,我们需要明确的点是👇
主要工作流程
梳理起来,可以把TLS 1.2 握手过程分为主要的五步👇
图片内容来自浪里行舟
步骤(1)
Client发起一个HTTPS请求,连接443端口。这个过程可以理解成是请求公钥的过程。
步骤(2)
Server端收到请求后,通过第三方机构私钥加密,会把数字证书(也可以认为是公钥证书)发送给Client。
步骤(3)
步骤(4)
在安全拿到服务器公钥后,客户端Client随机生成一个对称密钥,使用服务器公钥(证书的公钥)加密这个对称密钥,发送给Server(服务器)。
步骤(5)
Server(服务器)通过自己的私钥,对信息解密,至此得到了对称密钥,此时两者都拥有了相同的对称密钥。
接下来,就可以通过该对称密钥对传输的信息加密/解密啦,从上面图举个例子👇
接下来考虑一个问题,如果公钥被中间人拿到纂改怎么办呢?
以下图片来自leocoder
客户端可能拿到的公钥是假的,解决办法是什么呢?
第三方认证
客户端无法识别传回公钥是中间人的,还是服务器的,这是问题的根本,我们是不是可以通过某种规范可以让客户端和服务器都遵循某种约定呢?那就是通过第三方认证的方式
在HTTPS中,通过 证书 + 数字签名来解决这个问题。
这里唯一不同的是,假设对网站信息加密的算法是MD5,通过MD5加密后,然后通过第三方机构的私钥再次对其加密,生成数字签名。
这样子的话,数字证书包含有两个特别重要的信息👉某网站公钥+数字签名
我们再次假设中间人截取到服务器的公钥后,去替换成自己的公钥,因为有数字签名的存在,这样子客户端验证发现数字签名不匹配,这样子就防止中间人替换公钥的问题。
那么客户端是如何去对比两者数字签名的呢?
数字签名作用
数字签名:将网站的信息,通过特定的算法加密,比如MD5,加密之后,再通过服务器的私钥进行加密,形成加密后的数字签名。
第三方认证机构是一个公开的平台,中间人可以去获取。
如果没有数字签名的话,这样子可以就会有下面情况👇
从上面我们知道,如果只是对网站信息进行第三方机构私钥加密的话,还是会受到欺骗。
因为没有认证,所以中间人也向第三方认证机构进行申请,然后拦截后把所有的信息都替换成自己的,客户端仍然可以解密,并且无法判断这是服务器的还是中间人的,最后造成数据泄露。
总结
SSL 连接断开后如何恢复?
一共有两种方法来恢复断开的 SSL 连接,一种是使用 session ID,一种是 session ticket。
通过session ID
使用 session ID 的方式,每一次的会话都有一个编号,当对话中断后,下一次重新连接时,只要客户端给出这个编号,服务器如果有这个编号的记录,那么双方就可以继续使用以前的秘钥,而不用重新生成一把。目前所有的浏览器都支持这一种方法。但是这种方法有一个缺点是,session ID 只能够存在一台服务器上,如果我们的请求通过负载平衡被转移到了其他的服务器上,那么就无法恢复对话。
通过session ticket
另一种方式是 session ticket 的方式,session ticket 是服务器在上一次对话中发送给客户的,这个 ticket 是加密的,只有服务器能够解密,里面包含了本次会话的信息,比如对话秘钥和加密方法等。这样不管我们的请求是否转移到其他的服务器上,当服务器将 ticket 解密以后,就能够获取上次对话的信息,就不用重新生成对话秘钥了。
短轮询、长轮询和 WebSocket 间的区别?
短轮询
短轮询的基本思路:
响应。
优缺点👇
优点是比较简单,易于理解。
缺点是这种方式由于需要不断的建立 http 连接,严重浪费了服务器端和客户端的资源。当用户增加时,服务器端的压力就会变大,这是很不合理的。
长轮询
长轮询的基本思路:
首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将
这个请求挂起,然后判断服务器端数据是否有更新。
如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
优缺点👇
长轮询和短轮询比起来,它的优点是明显减少了很多不必要的 http 请求次数,相比之下节约了资源。
长轮询的缺点在于,连接挂起也会导致资源的浪费。
WebSocket
说一说正向代理和反向代理
正向代理
我们常说的代理也就是指正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求。
反向代理
这种代理模式下,它隐藏了真实的服务端,当我们向一个网站发起请求的时候,背后可能有成千上万台服务器为我们服务,具体是哪一台,我们不清楚,我们只需要知道反向代理服务器是谁就行,而且反向代理服务器会帮我们把请求转发到真实的服务器那里去,一般而言反向代理服务器一般用来实现负载平衡。
负载平衡的两种实现方式?
一种是使用反向代理的方式,用户的请求都发送到反向代理服务上,然后由反向代理服务器来转发请求到真实的服务器上,以此来实现集群的负载平衡。
另一种是 DNS 的方式,DNS 可以用于在冗余的服务器上实现负载平衡。因为现在一般的大型网站使用多台服务器提供服务,因此一个域名可能会对应多个服务器地址。当用户向网站域名请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。这种方式有一个缺点就是,由于 DNS 服务器中存在缓存,所以有可能一个服务器出现故障后,域名解析仍然返回的是那个 IP 地址,就会造成访问的问题。
参考
❤️ 感谢大家
如果你觉得这篇内容对你挺有有帮助的话:
作者:TianTianUP链接:https://juejin.im/post/6856546833025237006来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
The text was updated successfully, but these errors were encountered: