浏览器
浏览器资源解析渲染
解析渲染流程
-
浏览器开始解析 HTML,构造DOM树。当解析器遇到非阻塞资源(图片等)会请求资源并继续解析;遇到CSS也会继续解析;遇到script标签(特别是没有async和defer属性的)会阻塞渲染停止HTML解析。
-
处理CSS并构建CSSOM树,同时解析编译JavaScript文件。
-
将CSSOM和DOM合成一个渲染树,渲染步骤包括样式、布局、绘制,在某些情况下还包括合成。
CSS会阻塞浏览器渲染,会阻塞后续JS执行;JS会阻塞浏览器解析;IMG不会阻塞。
问题一:CSS放在头部的原因?Script放在尾部的原因?
-
放在尾部,html解析不受影响,浏览器会在样式加载解析完后,重新计算样式绘制,造成回流重绘、页面闪动等现象。
-
浏览器遇到script会立即下载执行,会阻塞html解析。如果js脚本加载时间太长,会造成页面长时间未响应。
问题二:DOM和CSSOM构建顺序关系
构建DOM树和CSSOM树是并行的;所以CSS加载不会阻塞DOM解析,但渲染树需要同时依赖两者,所以会阻塞DOM渲染。
浏览器安全
XSS
跨站脚本攻击。指攻击者在返回的HTML中嵌入javascript脚本,从而拿到用户信息并进行操作。分三种类型:
存储型
将脚本存储到服务器数据库,然后在客户端执行脚本达到攻击效果。常见于:评论区提交一段脚本代码,如果前后端没有做好转义,存储到数据库后,在客户端渲染时直接执行。
反射型
恶意脚本作为请求URL参数,浏览器解析后执行。与存储型不同,服务器不会存储这些恶意脚本。
文档型
与反射型相同,恶意脚本被作为请求URL的参数。区别在于JS取出URL中的恶意代码执行。
防范措施
-
转义和过滤:对引号、尖括号、斜杠进行转义;过滤则把script标签过滤掉
-
利用HttpOnly:cookie设置HttpOnly,禁止js脚本访问cookie。
-
CSP:浏览器内容安全策略,只允许加载指定域脚本及样式。
CSRF
跨站请求伪造,即黑客诱导用户跳转恶意网站,利用用户登陆态发起恶意请求。原理是http请求会携带cookie。
防范措施
-
SameSite Cookie:该属性表示cookie不会随着跨域请求发送,减少CSRF攻击;
-
Origin和Referer:验证Referer是否从第三方网站发出,组织第三方网站请求,但可以通过ajax自定义请求头方式伪造。
-
CSRF Token: 客户端向服务器请求token,然后在所有请求中带上。
SQL注入
把SQL命令插入web表单、页面请求的查询字符串中提交到服务器,达到欺骗服务器执行恶意SQL命令到效果。
防范措施
-
对用户输入进行校验,通过正则表达式,或限制长度、对单 # 以及双 - 进行转换
-
不要使用动态拼装SQL,使用参数化SQL或进行直接使用存储过程进行数据查询存取。
-
不要使用管理员权限进行数据库链接。
-
不要把机密信息明文存放,加密货hash掉密码和敏感信息。
点击劫持
一种视觉欺骗的攻击手段,将需要攻击的网站通过iframe嵌套在自己网页中,并将iframe设置透明,在页面中透出一个按钮诱导点击。
防范措施
使用 X-FRAME-OPTIONS,是一个HTTP响应投,防止iframe嵌套的点击挟持攻击。有三个值可选:
-
DENY
,表示页面不允许通过iframe
的方式展示 -
SAMEORIGIN
,表示页面可以在相同域名下通过iframe
的方式展示 -
ALLOW-FROM
,表示页面可以在指定来源的iframe
中展示
分析CSRF和XSS区别
两者的原理区别:CSRF
是利用 网站A
本身的漏洞,去请求 网站A
的 api
。而 XSS
是向网站A
注入 JS
代码,然后执行 JS
里的代码,篡改网站A
的内容。
CSRF
仅仅是利用了http
携带cookie
的特性进行攻击的,但是无法得到被攻击站点的cookie
。这个和XSS
不同,XSS
一般是直接通过拿到Cookie
等信息进行攻击的。
浏览器本地存储
cookie
最早的本地存储方式,大小只有4kb,是一种纯文本文件,每次发起HTTP请求都会携带。具备以下特点:
-
一旦创建无法修改
-
无法跨域名,即不同域名无法共享,能阻止非法获取其他网站cookie。如果需要共享,可以使用以下方法:
-
使用Nginx反向代理
-
在一个站点登陆之后,往其他网站写Cookie。服务端的Session存储到一个节点,Cookie存储sessionId。
-
-
每个域名下不超20个。
-
cookie数据保存在客户端。
-
有效期可以通过Expires 和 Max-age设置。
使用场景:
-
最常见的使用场景就是Cookie和session结合使用,我们将sessionId存储到Cookie中,每次发请求都会携带这个sessionId,这样服务端就知道是谁发起的请求,从而响应相应的信息。
-
可以用来统计页面的点击次数
sessionStorage
用于临时保存同一窗口/标签页数据,刷新页面不会删除,关闭页面会被删除。具备以下特点:
-
在本地进行数据存储
-
同名策略限制,且只有在同一浏览器同一窗口下才能共享
-
不能被爬虫获取。
localStorage
存储较大的信息,具备以下特点:
-
大小有5MB,可以存储更多信息。
-
持久存储,不会随页面消失,除非主动清除。
-
仅存储在本地,请求不会携带。
-
存在兼容性问题,IE8以下版本不支持
-
如果设置隐私模式,则无法读取localStorage
-
受同源策略限制。
同源策略:protocol(协议)、domain(域名)、port(端口)必须全部一致
主要目的:保护用户的信息安全,只是对js脚本的限制,不对浏览器限制。
浏览器缓存
浏览器每次发起请求,都会在浏览器缓存中查找该请求结果以及缓存标识。收到返回的请求结果都会将结果和缓存标识存入浏览器缓存。缓存类型:
强缓存
在缓存期间不需要重新发生请求。通过设置两种HttpHeader实现:Expires和
Cache-Control。
字段 | 协议版本 | 值代表 | 响应头 | 请求头 | 补充 |
---|---|---|---|---|---|
Expires | HTTP1.0 | 服务端时间 | ✔️ | ❌ | 受限本地时间 |
Cache-Control | HTTP1.1 | 表示资源会在多少秒后过期需要再次请求 | ✔️ | ✔️ | 优先级高于Expires |
协商缓存
由服务器决定是否缓存,若协商缓存失败则返回200,生效则返回304。
协商缓存主要有Last-Modified和Etag两个属性
Last-Modified:服务器在响应请求时,会告诉浏览器资源的最后修改时间。
浏览器接收到后,如果再次请求,会在请求头中携带If-Modified-Since
字段,这个字段的值也就是服务器传来的最后修改时间,服务器拿到请求头中的If-Modified-Since
字段后,其实会和这个服务器中该资源的最后修改时间
对比。但是存在一定弊端因为是按照秒为单位的,如果是毫秒性操作,可能会存在一定误差,因此很少使用。
Etag:服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识。
浏览器接收到后,如果再次请求,会在请求头中携带If-None-Match
字段,这个字段的值也就是服务器生成的唯一标识,服务器拿到请求头中的If-None-Match
字段后,其实会和这个服务器中的唯一标识进行对比。协商缓存常用此属性。
启发式缓存
只有在没有明确缓存策略时,会激活启发式缓存。所以要合理设置缓存,否则会因没有设置缓存时间等原因,导致内容缓存不刷新。
图解
缓存位置
-
Service Worker
:是运行在浏览器背后的独立线程,无法直接访问DOM
,但可以用来做离线缓存
、消息推送
和网络代理
。传输协议必须为HTTPS
。 -
Memory Cache
:内存中的缓存 -
Disk Cache
:存储在硬盘中的缓存 -
Push Cache
:(推送缓存
)是HTTP/2
中的内容;
注:
HTTP2
的服务器推送功能,在Chrome106
版本后不可用;
跨域
受同源策略限制,部分行为无法跨域。而跨域的手段有以下几种:
CORS跨域
是一种机制,W3C的标准。允许浏览器向跨域服务器发出XMLHttpRequest或者Fetch请求。整个CORS通信过程有浏览器自行完成,不需要用户参与。浏览器会根据服务端响应的 header
(Access-Control-Allow-origin
) 进行判断,如果响应支持跨域,则继续发出正常请求,如果不支持,则在控制台显示错误。
简单请求
不会触发预检(OPTIONS请求)直接发出正常请求。同时满足以下条件则属于简单请求
-
使用 GET/HEAD/POST
-
请求头只包含安全信息:Accept/Accept-Language/Content-Language/Content-Type
-
Content-Type的值取三者之一:
text/plain
、multipart/form-data
、application/x-www-form-urlencoded
复杂请求
不满足简单请求条件的请求。在正式通信前,增加HTTP查询请求,即预检请求,通过预检请求查询服务器是否允许跨域请求。
Option
请求头中有一个Access-Control-Request-Method
字段(必需),表示在实际发出请求时将用什么请求方法
JSONP
利用<script>
标签没有跨域限制,通过该标签指向一个需要访问的地址并提供一个回调函数来接收数据。
postMessage 跨域
window.postMessage()
可以安全的实现跨域通信;我们只需要拥有另一个窗口的引用
,就可以传递消息给另一个窗口;通过onmessage
监听 传递过来的数据。
可以解决:页面与通过window.open打开的新页面的数据传递了;页面与嵌套的iframe消息传递。
跨域请求如何携带 cookie
例如我们想要在跨域请求中带上cookie
,需要满足以下条件:
-
Request
请求设置withCredentials
为true
-
samesite
值要设置为none
; -
服务器设置首部字段
Access-Control-Allow-Credentials
为true
-
服务器的
Access-Control-Allow-Origin
设置为*
或者对应的域名;
回流重绘
回流:渲染树元素布局发生改变时,重新生成布局,排列元素
重绘:渲染树中元素外观发生改变时,不影响布局,产生重绘
重绘不一定会引起回流,但回流一定会引起重绘
避免触发重绘回流
-
避免频繁使用style,采用修改class
-
使用
dispaly:none
做DOM离线处理。 -
对resize,scroll等进行防抖/节流处理
-
利用
CSS3
的transform
、opacity
、filter
这些属性可以实现合成
的效果,也就是GPU
加速。 -
将动画效果应用到
position
属性为absolute
或fixed
的元素上。
常见浏览器内核
如何做浏览器兼容?
常见问题
Cookie、Session、Token 有什么区别?
cookie是服务器发送到用户浏览器并保存在本地的数据。使基于无状态的HTTP协议记录稳定的状态信息成为可能。
session指在客户端和服务器之间建立的一种持续的交互状态。当用户首次访问网站时,服务器会为该用户生成一个唯一的会话标识符(Session ID)。这个标识符通常是一个随机的字符串,用于唯一标识用户的会话。生成的会话数据存储在服务器中,服务器会将生成的Session ID发送给客户端。客户端的浏览器会将接收到的会话 cookie 存储在本地。每次客户端向服务器发送请求时,会自动将 cookie 包含在请求头中,从而使服务器能够识别用户的会话。
token是一种用于进行身份验证和授权的令牌,通常由服务器生成并发送给客户端。与 Session 不同,Token 是无状态的,它包含了所有必要的信息以验证用户身份和访问权限,因此不需要在服务器端存储任何会话数据。常见的 Token 包括基于JSON Web Token(JWT)。token支持跨域。
计算机网络
状态码
-
200:请求成功
-
304:协商缓存
-
400:请求有误,服务器没有进行新建/修改数据操作
-
401:用户没有权限(令牌/密码错误)
-
403:用户得到授权却禁止访问
-
404:Not found
-
405:请求方法不允许
-
500:服务器发生错误
-
502:网关错误
-
503:服务不可用
-
504:网关超时
GET 和 POST
常见HTTP请求方法
-
GET: 向服务器获取数据;
-
POST:将实体提交到指定的资源,通常会造成服务器资源的修改;
-
PUT:上传文件,更新数据;
-
DELETE:删除服务器上的对象;
-
HEAD:获取报文首部,与GET相比,不返回报文主体部分;
-
OPTIONS:询问支持的请求方法,用来跨域请求;
-
CONNECT:要求在与代理服务器通信时建立隧道,使用隧道进行TCP通信;
-
TRACE: 回显服务器收到的请求,主要⽤于测试或诊断。
GET
通常用于从服务器获取资源,参数会被附加在URL末尾,用&符隔开。总结一下特点:
-
可以从服务端获取数据
-
参数暴露在URL中,存在安全隐患
-
URL长度受限,根据浏览器不同长度也不同。
-
具有幂等性,多次请求得到结果相同。
-
响应结果可以被缓存。
POST
通常用于向服务器提交数据或创建新资源。请求数据放在请求体里。总结以下特点:
-
参数在请求体里,较为安全隐蔽
-
请求体大小没有限制,可以传输大量数据
-
默认不具有幂等性,多次请求可能得到不同结果。
-
响应结果默认不会被浏览器缓存。
幂等性:调用方,对系统进行重复调用,不论次数多少,结果对系统的影响都是相同的效果。
URL到页面呈现
-
解析URL
-
缓存判断:检查是否有本地强缓存可用,可用则从缓存中返回资源。
-
DNS解析:通过递归查询和迭代查询解析域名得到域名IP地址;
-
查询顺序:浏览器IP -> 操作系统IP -> Hosts文件 -> DNS根服务器
DNS:域名服务器,域名和IP地址互相映射到分布式数据库。
DNS协议运行在UDP协议,使用端口53
-
-
获取MAC地址
-
TCP三次握手
-
发送请求:请求时会携带上cookie和缓存标识字段。
-
HTTPS握手:如果是HTTPS协议,通信前还会有一个四次握手的过程,
-
返回数据,接收响应:
connection:keep-alive
的值来选择通过四次挥手
来断开TCP
连接,或者保留; -
页面渲染:浏览器解析渲染
TCP
面对连接的传输层协议。可靠的,基于字节流的;具有超时重传、拥塞控制机制。
可靠性:具备确认应答ACK和序列号实现可靠传输。
基于字节流:将一条用户消息根据滑动窗口的字节大小,拆分成多个
TCP
报文段(TCP将数据看作一连串字节流
)
为什么TCP是可靠的?
依靠以下六种机制保证可靠性。
-
TCP校验和:是端到端的校验和。发送端计算,接收端验证。目的:发现TCP首部和数据在发送端到接收端之间发生的任何改动。
-
确认应答和序列号
-
确认应答:如果特定时间内没有收到接受端的ACK,发送端会重新发送数据
-
序列号机制防止了有网络延迟的情况下发送端不断发送相同数据的情况。
-
-
超时重传:发送数据时设置一个定时器,超时没收到ACK则重传
-
连接管理:三次握手四次挥手
-
流量控制:控制发送端发送书读,避免接收不过来造成丢包和网络拥塞(滑动窗口)
-
拥塞控制:避免发送端的数据填满整个网络
-
主要算法:慢启动、拥塞避免、拥塞发生
-
三次握手
为什么要进行三次握手?
目的:为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
三次握手可以同步双方初始序列号。TCP通信的双方都要确保初始序列号能被可靠的同步。这个序列号可以标识发送出去的数据包中哪些是已经被对方收到的。如果是二次握手的话只能保证一方的序列号被正确的接收,难以保证同步。
三次握手的流程
-
客户端发送
SYN
报文到服务端发起握手, 成功让服务端知道了客户端具有发送能力 -
服务端收到
SYN
报文之后回复SYN
和ACK
报文给客户端,成功让客户端知道了服务端具有接收和发送能力,但此时服务端并不知道客户端是否接收到了自己发送的消息(如果服务端这时立刻给客户端发送数据,这个时候客户端可能还没有准备好接收数据) -
客户端收到
SYN
和ACK
,向服务端发送一个ACK
报文,让服务端知道了客户端做好了接收自己发送的消息的准备。
四次挥手
因为TCP是全双工通信,不能单方面完全断开链接。
为什么是四次挥手?
服务端收到客户端发送的FIN包后,可能还有没有发送完的数据,所以先回复一个ACK确认包,表示已经收到了FIN包,等服务端将剩余数据发送完毕之后再发送一个FIN包给客户端表示已经没有要发送的数据了,可以结束了连接了。所以是四次挥手而不是三次。
四次挥手流程
-
客户端发送
FIN
给服务端 -
服务端回复
ACK
给客户端,服务端还可以继续向客户端发送数据(若数据没有发送完) -
服务端发送
FIN
给客户端 -
客户端回复
ACK
给服务端,客户端经过2MSL
的时间后断开,服务端接收到了客户端发出的ACK
后立刻断开了到客户端的连接
等待2MSL的意义:如果最后一个ACK丢失,服务端没有收到ACK就会发起重传。确保服务端收到自己的ACK
1 个
MSL
确保第四次挥手
中主动关闭方
最后的ACK
报文最终能达到对端1 个
MSL
确保对端没有收到ACK
重传的FIN
报文可以到达
未整理全。。。 待补充。。。
作者-麦浪冒险家,欢迎关注!