1. 缓存
输入url, 有可能触发缓存,如出现主动补全网址就证明之前访问过,有缓存,访问时我们可以打开调试查看静态资源都是本地缓存获取的,缓存有强制缓存和协商缓存
协商缓存:
- Last-Modified和If-Modified-Since
- ETag和If-None-Match
Last-Modified和ETag对比
Last-Modified是最后的修改时间,Etag是基于内容做的一个唯一标识,优先使用Etag
- 如果一秒内多次更改,Last-Modified无法体现
- 打开文件,但没有修改,Last-Modified无法解决
- 有负载均衡的服务器生成的时间可能也不一样,Last-Modified无法解决
- Etag需要服务器计算生成,有消耗,
强制缓存:
- Expires
- Cache-Control
Expires和Cache-Control的区别
Expires 用来指定资源到期的时间,受限于本地时间,功能单一
Cache-Control功能更强大,常用选项:
- public: 所有服务器都可缓存
- private: 仅有客户端可以缓存
- max-age: 最大缓存时间
- no-cache: 强制使用协商缓存验证
- no-store: 不使用强制缓存,也不使用协商缓存
- only-if-cached: 表示不进行网络请求,完全只使用缓存,若缓存不命中,则返回503错误
2. HSTS
简单来说就是必须使用https访问, 而且当证书出现问题时,用户无法绕过警告。当第一次通过HTTPS请求网站,如果存在Strict-Transport-Security头,浏览器记录下这些信息,然后后面尝试访问这个网站的请求都会自动把HTTP替换为HTTPS。
出现原因:
大部分用户会偷懒,直接访问没有前缀的网址如:baidu.com, 之前版本的浏览器会默认访问http,然后重定向到https, 这一步容易导致ssl剥离攻击
不足:
如果我们第一次访问的不是https,浏览器会忽略Strict-Transport-Security,所以各大浏览器都维护一个预加载HSTS列表,在列表的网站强制访问https, 这个列表是随浏览器版本进行更新的,无法随意修改。
3. DNS
DNS服务器:
- 根服务器:只有13台根服务器,通过根服务器可以查询域名所属的顶级服务器
- 顶级服务器:顶级服务器对应一个顶级域名,如com/net/org/cn/edu/…,通过顶级域服务器可以查询二级域。
- 权威服务器:权威服务器对应二级域,如baidu.com/qq.com,
DNS解析过程
- 浏览器的 DNS 缓存
- 操作系统中的 DNS 缓存
- 操作系统的hosts文件(可手动写入的缓存/etc/hosts)
- 路由DNS缓存
- 运营商DNS缓存
- 递归查询: 本地DNS服务器(运营商维护)向根服务器查询,根服务器返回域名所属的顶级服务器,本地DNS服务器查询顶级服务器,顶级服务器返回域名所在的权威服务器,本地DNS服务器向权威服务器查询得到ip地址
- 本地服务器把结果返回给用户电脑
DNS预解析
// dns解析提前
<link rel="dns-prefetch" href="xxx.com">
// dns解析、建立连接时间(Socket) + SSL认证时间都提前
<link rel="preconnect" href="https://ajax.googleapis.com">
复制代码
http页面下所有的a标签的href都会自动启用DNS Prefetch,https页面需要使用meta标签强制开启
<meta http-equiv="x-dns-prefetch-control" content="on">
复制代码
https
三次握手
- 客户端发送带有SYN标识(SYN=1,seq=x)的请求报文段,然后进入SYN_SEND状态,等待服务端确认;
- 服务端接收到客户端SYN报文段后,需要发送ACK信息对这个SYN进行确认,同时还要发送自己的SYN信息(SYN=1,ACK=1,seq=y,ack=x+1)服务端把这些信息放在一个报文段中((SYN+ACK报文段),一并发给客户端,此时客户端进入SYN_RECV状态;
- 客户端接收到服务端的SYN+ACK报文段后会向服务端发送ACK(ACK=1,seq=x+,ack=y+1)确认报文段,这个报文段发送后,客户端和服务端都进入ESTABLISHED状态,完成三次握手。
四次挥手
- 第一次挥手 由浏览器发给服务器 我的东西接受完了,你关闭把
- 第二次挥手 由服务器发给浏览器 我还有一些东西要发送,你等一会(我要验证发送数据的完整性)当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定
- 第三次挥手 由服务器发给浏览器 我发送完了,你断开吧
- 第四次挥手 由浏览器发给服务器 好的,我断开了
为什么是三次握手,不是两次
保证双方都有接收数据的能力
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
多了确认断开的步骤,第二次挥手是回复收到断开的请求,但是如果有正在传输的数据,可以选择继续发送,第三次挥手才是服务器通知浏览器我这边完事了,
为什么客户端最后还要等待2MSL?
2MSL是一段TCP报文在传输过程中的最大生命周期,确保服务器收到最后一次发送的ACK报文。如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端会再次向服务器端发出ACK确认报文,
TCP是通过什么机制保障可靠性的?
滑动窗口: 可靠,有序,稳定, 拥塞控制: 慢启动, 加法增大、乘法减小,超时重传,选择性应答
浏览器解析html
- 构建dom树,
- 构建cssom树
- 合成render树
- 布局
- 绘制
常用指标名称
- FP: 第一次绘制,通常这时候只能显示背景图片等,没有实际上的DOM
- FCP: 第一次带有DOM内容的渲染
- FMP: 有意义的绘制, 可以触发交互了
阻塞
css会阻塞render树的构建,js会阻塞dom树的构建,由于js常常会修改css, css会阻塞js,
<head>
<link rel="stylesheet" href="./static/style.css">
<script src="./static/index.js"></script> // 上方的css文件解析会阻塞下面的js,需要等待cssom树构建完成
</head>
复制代码
js阻塞dom树的构建,这时可以在页面上看到dom吗?
可以看到阻塞之前的dom(如果有的话),浏览器将会在所有CSS就绪之后,开始进行一次提前渲染,有什么显示什么
async defer
- async: js下载是异步的,下载完立刻执行
- defer: js下载异步,页面解析完后执行
preload prefetch
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">
<link rel="prefetch" href="/script.js" as="script">
复制代码
-
preload: 可以强制浏览器请求资源,同时不阻塞文档onload事件
-
prefetch: 告诉浏览器这个资源将来可能需要,但是什么时间加载这个资源是由浏览器来决定的。 若能预测到用户的行为,比如懒加载,点击到其它页面等则相当于提前预加载了需要的资源。
-
preload 加载字体解决闪动问题, 加载非首屏资源,优化体验
-
prefetch加载用户可能点击的页面
重排(reflow)和重绘(repaint)
- 重绘:某些元素的外观被改变,例如:颜色
- 重排:重新生成布局,重新排列元素, 查询某些属性如offsetTop也会触发
触发重绘的属性: width height margin padding position overflow offsetTop ... 触发重排的属性: color background border-radius ......
如何减少重排和重绘
- 动态改变类而不是直接改变样式
- 避免频繁操作,可以创建一个documentFragment或div,更改完成后再添加到,也可以在
display:none
的元素上进行操作,最终把它显示出来。这样不会引发过多的重排和重绘。 - 动画元素可以使用
absolute
或fixed
脱离文档流,动画可以开启cpu加速,常用属性有:transform, opacity, filter