博客原文地址:https://finget.github.io/view…
前置内容 浏览器次要过程
浏览器是多过程的,次要分为:
- 浏览器主过程:只有一个,次要管制页面的创立、销毁、网络资源管理、下载等。
- 第三方插件过程:每一种类型的插件对应一个过程,仅当应用该插件时才创立。
- GPU 过程:最多一个,用于 3D 绘制等。
- 浏览器渲染过程(浏览器内核):每个 Tab 页对应一个过程,互不影响。
第一局部 输出网址并解析
这里咱们只思考输出的是一个 URL 构造字符串,如果是非 URL 构造的字符串,则会用浏览器默认的搜索引擎搜寻该字符串。
URL 的组成
URL 次要由 协定
、 主机
、 端口
、 门路
、 查问参数
、 锚点
6 局部组成!
解析 URL
输出 URL 后,浏览器会解析出协定、主机、端口、门路等信息,并结构一个 HTTP 申请。
- 浏览器发送申请前,依据申请头的
expires
和cache-control
判断是否命中(包含是否过期)强缓存策略,如果命中,间接从缓存获取资源,并不会发送申请。如果没有命中,则进入下一步。 - 没有命中强缓存规定,浏览器会发送申请,依据申请头的
last-modified
和etag
判断是否命中协商缓存,如果命中,间接从缓存获取资源。如果没有命中,则进入下一步。 - 如果前两步都没有命中,则间接从服务端获取资源。
HSTS
因为安全隐患,会应用 HSTS 强制客户端应用 HTTPS 拜访页面。详见:你所不晓得的 HSTS。
当你的网站均采纳 HTTPS,并合乎它的平安标准,就能够申请加入 HSTS 列表,之后用户不加 HTTPS 协定再去拜访你的网站,浏览器都会定向到 HTTPS。无论匹配到没有,都要开始 DNS 查问工作了。
浏览器缓存
强缓存
强制缓存就是向浏览器缓存查找该申请后果,并依据该后果的缓存规定来决定是否应用该缓存后果的过程。强缓存又分为两种 Expires
和Cache-Control
Expires
- 版本:HTTP/1.0
- 起源:存在于服务端返回的响应头中
- 语法:Expires: Wed, 22 Nov 2019 08:41:00 GMT
- 毛病:服务器的工夫和浏览器的工夫可能并不统一导致生效
Cache-Control
- 版本:HTTP/1.1
- 起源:响应头和申请头
- 语法:Cache-Control:max-age=3600
- 毛病:工夫最终还是会生效
申请头:
字段名称 | 阐明 |
---|---|
no-cache | 告知 (代理) 服务器不间接应用缓存,要求向原服务器发动申请 |
no-store | 所有内容都不会被保留到缓存或 Internet 临时文件中 |
max-age=delta-seconds | 告知服务器客户端心愿接管一个存在工夫不大于 delta-secconds 秒的资源 |
max-stale[=delta-seconds] | 告知 (代理) 服务器客户端违心接管一个超过缓存工夫的资源,若有定义 delta-seconds 则为 delta-seconds 秒,若没有则为任意超出工夫 |
min-fresh=delta-seconds | 告知 (代理) 服务器客户端心愿接管一个在小于 delta-seconds 秒内被更新过的资源 |
no-transform | 告知 (代理) 服务器客户端心愿获取实体数据没有被转换 (比方压缩) 过的资源 |
noly-if-cached | 告知 (代理) 服务器客户端心愿获取缓存的内容(若有), 而不必向原服务器发去申请 |
cache-extension | 自定义扩大值,若服务器不辨认该值将被疏忽掉 |
响应头:
字段名称 | 阐明 |
---|---|
public | 表明任何状况下都得缓存该资源(即便是须要 HTTP 认证的资源) |
Private=[field-name] | 表明返回报文中全副或局部 (若指定了 field-name 则为 field-name 的字段数据) 仅凋谢给某些用户 (服务器指定的 share-user,如代理服务器) 做缓存应用,其余用户则不能缓存这些数据 |
no-cache | 不间接应用缓存,要求向服务器发动 (新鲜度校验) 申请 |
no-store | 所以内容都不会被保留到缓存或 Internet 临时文件中 |
no-transform | 告知客户端缓存文件时不得对实体数据做任何扭转 |
noly-if-cached | 告知 (代理) 服务器客户端心愿获取缓存的内容(若有), 而不必向原服务器发去申请 |
must-revalidate | 以后资源肯定是向原办法服务器发去验证申请的,如申请是吧会返回 504(而非代理服务器上的缓存) |
proxy-revalidate | 与 must-revalidate 相似,但仅能利用于共享缓存(如代理) |
max-age=delta-seconds | 告知客户端该资源在 delta-seconds 秒内是陈腐的,无需向服务器发申请 |
s-maxage=delta-seconds | 同 max-age,但仅能利用于共享缓存(如代理) |
cache-extension | 自定义扩大值,若服务器不辨认该值将被疏忽掉 |
示例:
// server.js
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {console.log('request come', request.url)
if (request.url === '/') {const html = fs.readFileSync('test.html', 'utf8')
response.writeHead(200, {'Content-Type': 'text/html'})
response.end(html)
}
if (request.url === '/script.js') {
response.writeHead(200, {
'Content-Type': 'text/javascript',
'Cache-Control': 'max-age=20,public' // 缓存 20s 多个值用逗号离开
})
response.end('console.log("script loaded")')
}
}).listen(8888)
console.log('server listening on 8888')
// test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
<script src="/script.js"></script>
</html>
协商缓存
协商缓存就是强制缓存生效后,浏览器携带缓存标识向服务器发动申请,由服务器依据缓存标识决定是否应用缓存的过程。
Last-Modified(响应头),If-Modified-Since(申请头)
在浏览器第一次给服务器发送申请后,服务器会在响应头中加上这个字段。
浏览器接管到后,如果再次申请,会在申请头中携带 If-Modified-Since
字段,这个字段的值也就是服务器传来的最初批改工夫。
服务器拿到申请头中的 If-Modified-Since
的字段后,其实会和这个服务器中该资源的最初批改工夫 Last-Modified
比照, 询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。
然而如果在本地关上缓存文件,就会造成 Last-Modified
被批改,所以在 HTTP / 1.1
呈现了 ETag
。
ETag(响应头)、If-None-Match(申请头)
ETag
是服务器依据以后文件的内容,给文件生成的惟一标识,只有外面的内容有改变,这个值就会变。服务器通过响应头把这个值给浏览器。
浏览器接管到 ETag 的值,会在下次申请时,将这个值作为 If-None-Match
这个字段的内容,并放到申请头中,而后发给服务器。
如果两种形式都反对的话,服务器会优先思考 ETag
存储地位
- Service Worker
Service Worker
是运行在浏览器背地的独立线程,个别能够用来实现缓存性能。应用 Service Worker
的话,传输协定必须为 HTTPS
。因为 Service Worker
中波及到申请拦挡,所以必须应用 HTTPS
协定来保障平安。Service Worker
的缓存与浏览器其余内建的缓存机制不同,它能够让咱们自在管制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
Service Worker
实现缓存性能个别分为三个步骤:首先须要先注册 Service Worker
,而后监听到 install
事件当前就能够缓存须要的文件,那么在下次用户拜访的时候就能够通过拦挡申请的形式查问是否存在缓存,存在缓存的话就能够间接读取缓存文件,否则就去申请数据。
当 Service Worker
没有命中缓存的时候,咱们须要去调用 fetch
函数获取数据。也就是说,如果咱们没有在 Service Worker
命中缓存的话,会依据缓存查找优先级去查找数据。然而不论咱们是从 Memory Cache
中还是从网络申请中获取的数据,浏览器都会显示咱们是从 Service Worker
中获取的内容。
- Memory Cache
Memory Cache
也就是内存中的缓存,次要蕴含的是以后中页面中曾经抓取到的资源, 例如页面上曾经下载的款式、脚本、图片等。读取内存中的数据必定比磁盘快, 内存缓存尽管读取高效,可是缓存持续性很短,会随着过程的开释而开释。一旦咱们敞开 Tab 页面,内存中的缓存也就被开释了。
那么既然内存缓存这么高效,咱们是不是能让数据都寄存在内存中呢?
这是不可能的。计算机中的内存肯定比硬盘容量小得多,操作系统须要精打细算内存的应用,所以能让咱们应用的内存必然不多。
须要留神的事件是,内存缓存在缓存资源时并不关怀返回资源的 HTTP 缓存头
Cache-Control
是什么值,同时资源的匹配也并非仅仅是对 URL 做匹配,还可能会对Content-Type
,CORS 等其余特色做校验。
- Disk Cache
Disk Cache
也就是存储在硬盘中的缓存,读取速度慢点,然而什么都能存储到磁盘中,比之 Memory Cache
胜在容量和存储时效性上。
- Push Cache
Push Cache
(推送缓存)是 HTTP/2
中的内容,当以上三种缓存都没有命中时,它才会被应用。它只在会话(Session)中存在,一旦会话完结就被开释,并且缓存工夫也很短暂,在 Chrome 浏览器中只有 5 分钟左右,同时它也并非严格执行 HTTP 头中的缓存指令。
- 所有的资源都能被推送,并且可能被缓存, 然而
Edge
和Safari
浏览器反对绝对比拟差 - 能够推送
no-cache
和no-store
的资源 - 一旦连贯被敞开,
Push Cache
就被开释 - 多个页面能够应用同一个
HTTP/2
的连贯,也就能够应用同一个Push Cache
。这次要还是依赖浏览器的实现而定,出于对性能的思考,有的浏览器会对雷同域名但不同的 tab 标签应用同一个 HTTP 连贯。 Push Cache
中的缓存只能被应用一次- 浏览器能够拒绝接受曾经存在的资源推送
- 你能够给其余域名推送资源
DNS 域名解析
在发动 http 申请之前,浏览器首先要做去取得咱们想拜访网页的 IP 地址,浏览器会发送一个 UDP 的包给 DNS 域名解析服务器。
递归查问
咱们的浏览器、操作系统、路由器都会缓存一些 URL 对应的 IP 地址,统称为 DNS 高速缓存。这是为了放慢 DNS 解析速度,使得不用每次都到根域名服务器中去查问。
迭代查问
迭代查问的形式就是,部分的 DNS 服务器并不会本人向其余服务器进行查问,而是把可能解析该域名的服务器 IP 地址返回给客户端,客户端会一直的向这些服务器进行查问,直到查问到了地位,迭代的话只会帮你找到相干的服务器,而后说我当初比较忙,你本人去找吧。
DNS 负载平衡
DNS 还有负载平衡的作用,当初很多网站都有多个服务器,当一个网站拜访量过大的时候,如果所有申请都申请在同一个服务器上,可能服务器就会崩掉,这时候就用到了 DNS 负载平衡技术,当一个网站有多个服务器地址时,在应答 DNS 查问的时候,DNS 服务器会对每个查问返回不同的解析后果,也就是返回不同的 IP 地址,从而把拜访疏导到不同的服务器下来,来达到负载平衡的目标。例如能够依据每台机器的负载量,或者该机器间隔用户的地理位置间隔等等条件。
第二局部 TCP/IP 连贯:三次握手
网络协议分层
TCP/IP 协定
TCP(Transmission Control Protocol)传输控制协议。
TCP/IP 协定将应用层、表示层、会话层合并为应用层,物理层和数据链路层合并为网络接口层。
TCP/IP 协定不仅仅指的是 TCP 和 IP 两个协定,⽽是指的⼀个由 FTP,SMTP,TCP,UDP,IP,ARP 等等协定形成的协定汇合。
三次握手
客服端和服务端在进行 http 申请和返回的工程中,须要创立一个 TCP connection
(由客户端发动),http
不存在连贯这个概念,它只有申请和响应。申请和响应都是数据包,它们之间的传输通道就是TCP connection
。
位码即 tcp 标记位,有 6 种标示:
- SYN(synchronous 建设联机)
- ACK(acknowledgement 确认)
- PSH(push 传送)
- FIN(finish 完结)
- RST(reset 重置)
- URG(urgent 紧急)
第一次握手:主机 A 发送位码为 SYN=1
,随机产生Seq number=1234567
的数据包到服务器,主机 B 由 SYN=1
晓得,A 要求建设联机;(第一次握手,由浏览器发动,通知服务器我要发送申请了)
第二次握手:主机 B 收到申请后要确认联机信息,向 A 发送 ack number=(主机 A 的 seq+1)
,SUN=1,ACK=1234567 + 1
,随机产生Seq=7654321
的包;(第二次握手,由服务器发动,通知浏览器我筹备承受了,你连忙发送吧)
第三次握手:主机 A 收到后查看 ack number
是否正确,即第一次发送的 seq number+1
,以及位码SYN
是否为 1,若正确,主机 A 会再发送 ack number=(主机 B 的 seq+1)
,ack=7654321 + 1
,主机 B 收到后确认Seq
值与 ACK=7654321+ 1
则连贯建设胜利;(第三次握手,由浏览器发送,通知服务器,我马上就发了,筹备承受吧)
总是要问:为什么须要三次握手,两次不行吗?其实这是由 TCP 的本身特点 牢靠传输 决定的。客户端和服务端要进行牢靠传输,那么就须要 确认单方的
接管
和发送
能力 。第一次握手能够确认客服端的发送能力
, 第二次握手,服务端SYN=1,Seq=Y
就确认了发送能力
,ACK=X+1
就确认了接管能力
, 所以第三次握手才能够确认客户端的接管能力
。不然容易呈现丢包的景象。
第三次握手的必要性?
试想如果是用两次握手,则会呈现上面这种状况:
如客户端收回连贯申请,但因连贯申请报文失落而未收到确认,于是客户端再重传一次连贯申请。起初收到了确认,建设了连贯。数据传输结束后,就开释了连贯,客户端共收回了两个连贯申请报文段,其中第一个失落,第二个达到了服务端,然而第一个失落的报文段只是在某些网络结点长时间滞留了,延误到连贯开释当前的某个工夫才达到服务端,此时服务端误认为客户端又收回一次新的连贯申请,于是就向客户端收回确认报文段,批准建设连贯,不采纳三次握手,只有服务端收回确认,就建设新的连贯了,此时客户端疏忽服务端发来的确认,也不发送数据,则服务端统一期待客户端发送数据,浪费资源。
什么是半连贯队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时单方还没有齐全建设其连贯,服务器会把此种状态下申请连贯放在一个队列里,咱们把这种队列称之为半连贯队列。
当然还有一个全连贯队列,就是曾经实现三次握手,建设起连贯的就会放在全连贯队列中。如果队列满了就有可能会呈现丢包景象。
这里在补充一点对于 SYN-ACK 重传次数的问题:
服务器发送完 SYN-ACK 包,如果未收到客户确认包,服务器进行首次重传,期待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过零碎规定的最大重传次数,零碎将该连贯信息从半连贯队列中删除。
留神,每次重传期待的工夫不肯定雷同,个别会是指数增长,例如间隔时间为 1s,2s,4s,8s…
ISN 是固定的吗?
当一端为建设连贯而发送它的 SYN 时,它为连贯抉择一个初始序号。ISN 随工夫而变动,因而每个连贯都将具备不同的 ISN。ISN 能够看作是一个 32 比特的计数器,每 4ms 加 1。这样抉择序号的目标在于避免在网络中被提早的分组在当前又被传送,而导致某个连贯的一方对它做谬误的解释。
三次握手的其中一个重要性能是客户端和服务端替换 ISN(Initial Sequence Number),以便让对方晓得接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因而 ISN 是动静生成的。
三次握手过程中能够携带数据吗?
其实第三次握手的时候,是能够携带数据的。然而,第一次、第二次握手不能够携带数据。
为什么这样呢? 大家能够想一个问题,如果第一次握手能够携带数据的话,如果有人要歹意攻打服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者基本就不理服务器的接管、发送能力是否失常,而后疯狂着重复发 SYN 报文的话,这会让服务器破费很多工夫、内存空间来接管这些报文。
也就是说,第一次握手不能够放数据,其中一个简略的起因就是会让服务器更加容易受到攻打了。而对于第三次的话,此时客户端曾经处于 ESTABLISHED 状态。对于客户端来说,他曾经建设起连贯了,并且也曾经晓得服务器的接管、发送能力是失常的了,所以能携带数据也没啥故障。
SYN 攻打?
服务器端的资源分配是在二次握手时调配的,而客户端的资源是在实现三次握手时调配的,所以服务器容易受到 SYN 洪泛攻打。SYN 攻打就是 Client 在短时间内伪造大量不存在的 IP 地址,并向 Server 一直地发送 SYN 包,Server 则回复确认包,并期待 Client 确认,因为源地址不存在,因而 Server 须要一直重发直至超时,这些伪造的 SYN 包将长时间占用未连贯队列,导致失常的 SYN 申请因为队列满而被抛弃,从而引起网络拥塞甚至零碎瘫痪。SYN 攻打是一种典型的 DoS/DDoS 攻打。
检测 SYN 攻打十分的不便,当你在服务器上看到大量的半连贯状态时,特地是源 IP 地址是随机的,基本上能够判定这是一次 SYN 攻打。在 Linux/Unix 上能够应用零碎自带的 netstats 命令来检测 SYN 攻打。
netstat -n -p TCP | grep SYN_RECV
常见的进攻 SYN 攻打的办法有如下几种:
- 缩短超时(SYN Timeout)工夫
- 减少最大半连接数
- 过滤网关防护
- SYN cookies 技术
第三局部 HTTP 申请
HTTP 倒退历史
HTTP/0.9
- [x] 只有一个命令 GET
- [x] 响应类型: 仅 超文本
- [x] 没有 header 等形容数据的信息
- [x] 服务器发送结束,就敞开 TCP 连贯
HTTP/1.0
- [x] 减少了很多命令(post HESD)
- [x] 减少
status code
和header
- [x] 多字符集反对、多局部发送、权限、缓存等
- [x] 响应:不再只限于超文本 (Content-Type 头部提供了传输 HTML 之外文件的能力 — 如脚本、款式或媒体文件)
HTTP/1.1
- [x] 长久连贯。TCP 三次握手会在任何连贯被建设之前产生一次。最终,当发送了所有数据之后,服务器发送一个音讯,示意不会再有更多数据向客户端发送了;则客户端才会敞开连贯(断开 TCP)
- [x] 反对的办法:
GET
,HEAD
,POST
,PUT
,DELETE
,TRACE
,OPTIONS
- [x] 进行了重大的性能优化和个性加强,分块传输、压缩 / 解压、内容缓存商量、虚拟主机(有单个 IP 地址的主机具备多个域名)、更快的响应,以及通过减少缓存节俭了更多的带宽
HTTP2
- [x] 所有数据以二进制传输。HTTP1.x 是基于文本的,无奈保障健壮性,HTTP2.0 相对应用新的二进制格局,不便且强壮
- [x] 同一个连贯外面发送多个申请不再须要依照程序来
- [x] 头信息压缩以及推送等提高效率的性能
HTTP3
- [x] QUIC“疾速 UDP 互联网连贯”(Quick UDP Internet Connections)
HTTP3 的次要改良在传输层上。传输层不会再有我后面提到的那些沉重的 TCP 连贯了。当初,所有都会走 UDP。
HTTP3 具体介绍
HTTP 协定特点
- 反对客户 / 服务器模式。
- 简略疾速客户向服务器申请服务时,只需传送申请办法和门路。申请办法罕用的有 GET、HEAD、POST。每种办法规定了客户与服务器分割的类型不同。因为 HTTP 协定简略,使得 HTTP 服务器的程序规模小,因此通信速度很快。
- 灵便:HTTP 容许传输任意类型的数据对象。正在传输的类型由 Content-Type(Content-Type 是 HTTP 包中用来示意内容类型的标识)加以标记。
- 无连贯:无连贯的含意是限度每次连贯只解决一个申请。服务器解决完客户的申请,并收到客户的应答后,即断开连接。采纳这种形式能够节俭传输工夫。
- 无状态:HTTP 协定是无状态协定。无状态是指协定对于事务处理没有记忆能力。短少状态意味着如果后续解决须要后面的信息,则它必须重传,这样可能导致每次连贯传送的数据量增大。另一方面,在服务器不须要先前信息时它的应答就较快。
当初 HTTP3 最快!
HTTP 报文
申请报文:
响应报文:
各协定与 HTTP 协定关系
- DNS 服务:解析域名至对应的 IP 地址
- HTTP 协定:生成针对指标 Web 服务器的 HTTP 申请报文
- TCP 协定:将申请报文按序号宰割成多个报文段
- IP 协定:搜寻对方的地址,一边直达一边传送
- TCP 协定:按序号以原来的程序重组申请报文申请的处理结果也同样利用 TCP/IP 协定向用户进行回传
- TCP 是底层通信协定,定义的是数据传输和连贯形式的标准;
- HTTP 是应用层协定,定义的是传输数据的内容的标准;
- HTTP 协定中的数据是利用 TCP 协定传输的,所以反对 HTTP 也就肯定反对 TCP。
对于 HTTP 的货色还有很多,我在最初放了张大图。
HTTPS
在 HTTP 的根底上再加一层 TLS(传输层安全性协定)或者 SSL(安全套接层),就形成了 HTTPS 协定。
HTTPS 默认工作在 TCP 协定 443 端口,它的工作流程个别如以下形式:
- TCP 三次同步握手
- 客户端验证服务器数字证书
- DH 算法协商对称加密算法的密钥、hash 算法的密钥
- SSL 平安加密隧道协商实现
- 网页以加密的形式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的 hash 算法进行数据完整性爱护,保证数据不被篡改。
- 客户端向服务端发送
Client Hello
音讯,其中携带客户端反对的协定版本、加密算法、压缩算法以及客户端生成的随机数; -
服务端收到客户端反对的协定版本、加密算法等信息后;
- 向客户端发送
Server Hello
音讯,并携带抉择特定的协定版本、加密办法、会话 ID 以及服务端生成的随机数; - 向客户端发送
Certificate
音讯,即服务端的证书链,其中蕴含证书反对的域名、发行方和有效期等信息; - 向客户端发送
Server Key Exchange
音讯,传递公钥以及签名等信息; - 向客户端发送可选的音讯
Certificate Request
,验证客户端的证书; - 向客户端发送
Server Hello Done
音讯,告诉服务端曾经发送了全副的相干信息;
- 向客户端发送
-
客户端收到服务端的协定版本、加密办法、会话 ID 以及证书等信息后,验证服务端的证书;
- 向服务端发送
Client Key Exchange
音讯,蕴含应用服务端公钥加密后的随机字符串,即预主密钥(Pre Master Secret
); - 向服务端发送
Change Cipher Spec
音讯,告诉服务端前面的数据段会加密传输; - 向服务端发送
Finished
音讯,其中蕴含加密后的握手信息;
- 向服务端发送
-
服务端收到
Change Cipher Spec
和Finished
音讯后;- 向客户端发送
Change Cipher Spec
音讯,告诉客户端前面的数据段会加密传输; - 向客户端发送
Finished
音讯,验证客户端的Finished
音讯并实现 TLS 握手;
- 向客户端发送
TLS 握手的关键在于利用通信双产生成的随机字符串和服务端的证书公钥生成一个单方通过协商后的对称密钥,这样通信单方就能够应用这个对称密钥在后续的数据传输中加密音讯数据,避免中间人的监听和攻打,保障通信平安。
HTTPS 连贯 须要 7 次握手,3 次 TCP + 4 次 TSL。
第四局部 服务器解决申请并返回 HTTP 报文
每台服务器上都会装置解决申请的利用——Web Server。常见的 Web Server 产品有 apache
、nginx
、IIS
或 Lighttpd
等。
HTTP 申请个别能够分为两类,动态资源 和 动静资源。
申请拜访动态资源,这个就间接依据 url 地址去服务器里找就好了。
申请动静资源的话,就须要 web server 把不同申请,委托给服务器上解决相应申请的程序进行解决(例如 CGI 脚本,JSP 脚本,servlets,ASP 脚本,服务器端 JavaScript,或者一些其它的服务器端技术等),而后返回后台程序解决产生的后果作为响应,发送到客户端。
服务器在解决申请的时候次要有三种形式:
- 第一种:是用一个线程来解决所有的申请,并且同时只能解决一个申请,然而这样的话性能是十分的低的。
- 第二种:是每一个申请都给他调配一个线程然而当链接和申请比拟多的时候就会导致服务器的 cpu 不堪重负。
- 第三种:就是采纳复用 I / O 的形式来解决例如通过 epoll 形式监督所有链接当链接状态产生扭转的时候才去调配空间进行解决。
第五局部 浏览器渲染页面
DOM 树
字节 → 字符 → 令牌 → 节点 → 对象模型。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div>![](awesome-photo.jpg)</div>
</body>
</html>
- 转换: 浏览器从磁盘或网络读取 HTML 的原始字节,并依据文件的指定编码(例如 UTF-8)将它们转换成各个字符。
- 令牌化: 浏览器将字符串转换成 W3C HTML5 标准规定的各种令牌,例如,“<html>”、“<body>”,以及其余尖括号内的字符串。每个令牌都具备非凡含意和一组规定。
- 词法剖析: 收回的令牌转换成定义其属性和规定的“对象”。
- DOM 构建: 最初,因为 HTML 标记定义不同标记之间的关系(一些标记蕴含在其余标记内),创立的对象链接在一个树数据结构内,此构造也会捕捉原始标记中定义的父项 - 子项关系: HTML 对象是 body 对象的父项,body 是 paragraph 对象的父项,依此类推。
CSS 对象模型 (CSSOM)
body {font-size: 16px}
p {font-weight: bold}
span {color: red}
p span {display: none}
img {float: right}
布局树 Layout Tree
- DOM 树与 CSSOM 树合并后造成渲染树。
- 渲染树只蕴含渲染网页所需的节点。
- 布局计算每个对象的准确地位和大小。
- 最初一步是绘制,应用最终渲染树将像素渲染到屏幕上。
渲染
渲染流程:
- 获取 DOM 后宰割为多个图层
- 对每个图层的节点计算款式后果(Recalculate style– 款式重计算)
- 为每个节点生成图形和地位(Layout– 重排, 回流)
- 将每个节点绘制填充到图层位图中(Paint– 重绘)
- 图层作为纹理上传至 GPU
- 组合多个图层到页面上生成最终屏幕图像(Composite Layers– 图层重组)
创立图层
<div class="position_">position</div>
<div class="box_3d">3d 变换 </div>
<div class="will-change">will-change</div>
<div class="transform"></div>
<iframe src="https://www.baidu.com"></iframe>
div {width: 100px;height: 100px;}
.position_ {background: pink;position: fixed;z-index: 20;}
.box_3d {background: red;transform: translate3d(100px,30px,10px);}
.will-change {background: #f12312;will-change: transform;}
.transform {background: #302912;transform: skew(30deg, 20deg);}
在 chrome 上查看 Layers.
如果没有关上 Layers, 按下图关上:
晓得图层的存在,咱们能够手动关上一个图层,通过增加
transform: translateZ(0)
这样回流和重绘的代价就小了,效率就会大大提高。然而不要滥用这个属性,否则会大大增加内存耗费。—— 开启 GPU 减速。
回流和重绘
- 重绘
当页面中元素款式的扭转并不影响它在文档流中的地位时(例如:color、background-color、visibility 等),浏览器会将新款式赋予给元素并从新绘制它,这个过程称为重绘。
- 回流
当 Render Tree 中局部或全副元素的尺寸、构造、或某些属性产生扭转时,浏览器从新渲染局部或全副文档的过程称为回流。
回流必将引起重绘,而重绘不肯定会引起回流。
引起回流:
- 页面首次渲染
- 浏览器窗口大小产生扭转
- 元素尺寸或地位产生扭转
- 元素内容变动(文字数量或图片大小等等)
- 元素字体大小变动
- 增加或者删除可见的 DOM 元素
- 激活 CSS 伪类(例如::hover)
- 查问某些属性或调用某些办法
引起回流的属性和办法:
- clientWidth、clientHeight、clientTop、clientLeft
- offsetWidth、offsetHeight、offsetTop、offsetLeft
- scrollWidth、scrollHeight、scrollTop、scrollLeft
- scrollIntoView()、scrollIntoViewIffNeeded()
- getComputedStyle()
- getBoundingClientRect()
- scrollTo()
如何缩小回流
- css
- 防止应用 table 布局;
- 尽可能在 DOM 树的最末端扭转 class;
- 防止设置多层内联款式;
- 将动画成果利用到 position 属性为 absolute 或 fixed 的元素上;
- 防止应用 CSS 表达式(例如:calc())。
- JS
- 防止频繁操作款式,最好一次性重写 style 属性,或者将款式列表定义为 class 并一次性更改 class 属性。
- 防止频繁操作 DOM,创立一个 documentFragment,在它下面利用所有 DOM 操作,最初再把它增加到文档中。
- 也能够先为元素设置 display: none,操作完结后再把它显示进去。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。
- 防止频繁读取会引发回流 / 重绘的属性,如果的确须要屡次应用,就用一个变量缓存起来。
- 对具备简单动画的元素应用相对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
第六局部 断开连接:TCP 四次离别
- 刚开始单方都处于 established 状态,如果是客户端先发动敞开申请
- 第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态
- 第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明曾经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态
- 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发送 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态
- 须要过一阵子以确保服务端收到本人的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于敞开连贯了,处于 CLOSED 状态。
挥手为什么须要四次?
因为当服务端收到客户端的 SYN 连贯申请报文后,能够间接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。然而敞开连贯时,当服务端收到 FIN 报文时,很可能并不会立刻敞开 SOCKET,所以只能先回复一个 ACK 报文,通知客户端,“你发的 FIN 报文我收到了”。只有等到我服务端所有的报文都发送完了,我能力发送 FIN 报文,因而不能一起发送。故须要四次挥手。
为什么客户端发送 ACK 之后不间接敞开,而是要等一阵子才敞开?
客户端收到服务端的连贯开释报文段后,对此收回确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入 TIME_WAIT(工夫期待)状态。此时 TCP 未开释掉,须要通过工夫期待计时器设置的工夫 2MSL 后,客户端才进入 CLOSED 状态。如果不期待,客户端间接跑路,当服务端还有很多数据包要给客户端发,且还在路上的时候,若客户端的端口此时刚好被新的利用占用,那么就接管到了无用数据包,造成数据包凌乱。
为什么 TIME_WAIT 状态须要通过 2MSL(最大报文生存工夫)能力返回到 CLOSE 状态?
实践上,四个报文都发送结束,就能够间接进入 CLOSE 状态了,然而可能网络是不牢靠的,有可能最初一个 ACK 失落。所以 TIME_WAIT 状态就是用来重发可能失落的 ACK 报文。
1 个 MSL 确保四次挥手中被动敞开方最初的 ACK 报文最终能达到对端;
1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文能够达到。
对于 HTTP
如果想要高清大图或者 Xmind 文件的话,能够私信 lian x
站在伟人的肩膀上
在这里对前辈大佬示意敬意,查找了很多材料,如有脱漏,还请见谅。文中如果有误,还望及时指出,感激!
5 分钟看懂 HTTP3
一文带你理解 HTTPS
从 URL 输出到页面展示到底产生什么?
从 URL 输出到页面展示到底产生什么?
在浏览器上申请一个 URL 的全副过程
前端经典面试题: 从输出 URL 到页面加载产生了什么?
浏览器缓存看这一篇就够了
从输出 URL 到浏览器显示页面的流程
在浏览器输出 URL 回车之后产生了什么(超具体版)
TCP 和 Http 的区别! 我都搞懂了, 你就别迷糊了!
为什么 HTTPS 须要 7 次握手以及 9 倍时延
渲染树构建、布局及绘制
浏览器渲染具体过程:重绘、重排和 composite 只是冰山一角
浏览器渲染机制和 Reflow(回流、重排)和 Repaint(重绘)
问我 Chrome 浏览器的渲染原理(6000 字长文)
浅谈浏览器的图层与重绘重排(具体),以及如何用于性能优化
HTTP 笔记 1:Web 根底及简略的 HTTP 协定
图解 HTTP-21 张图把 HTTP 安顿得明明白白
HTTP3
一文带你理解 HTTPS
浏览器工作原理与实际