1. 说一下 GET 和 POST 的区别?
GET在浏览器回退时是无害的,而POST会再次提交请求GET请求只能进行url 编码,而POST支持多种编码方式GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会保留GET请求参数通过URL 传递且参数是有长度限制的(2083 字符,中文字符的话只有 2083/9=231 个字符),而POST参数放在Request body中是没有限制的注意:
HTTP 协议未规定GET和POST的长度限制;GET的最大长度显示是因为浏览器和web 服务器限制了URI的长度。不同的浏览器和WEB 服务器,限制的最大长度不一样,要支持IE,则最大长度为 2083byte,若只支持Chrome,则最大长度 8182byte对参数的数据类型,
GET只接受ASCII 字符(如果非ASCII字符会进行转码),而POST没有限制GET和POST本质上就是TCP 连接,GET产生 一个TCP 数据包;POST产生 两个TCP 数据包注意:并不是所有浏览器都会在
POST中发送两次包,Firefox就只发送一次- 对于
GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应 200(返回数据) - 对于
POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应 200 ok(返回数据)
- 对于
2. HTTP1.0、HTTP1.1、HTTP2、HTTP3 的区别?
HTTP 1.0(1996 年)
- 任意数据类型都可以发送
- 有
GET、POST、HEAD三种方法 - 无法复用
TCP 连接(长连接) - 有丰富的请求响应头信息。以
header中的Last-Modified/If-Modified-Since和Expires作为缓存标识
HTTP 1.1(1997 年)
- 引入更多的请求方法类型
PUT、PATCH、DELETE、OPTIONS、TRACE、CONNECT - 引入
长连接,就是TCP 连接默认不关闭,可以被多个请求复用,通过请求头connection: keep-alive设置 - 引入
管道连接机制,可以在同一TCP连接里,同时发送多个请求 - 强化了缓存管理和控制
Cache-Control、ETag/If-None-Match - 支持
分块响应,断点续传,利于大文件传输,能过请求头中的Range实现
HTTP 2.0(2015 年)
- 使用新的
二进制协议,不再是纯文本,避免文本歧义,缩小了请求体积 多路复用,同域名下所有通信都是在单链接(双向数据流)完成,提高连接的复用率,在拥塞控制方面有更好的能力提升- 允许服务端主动推送数据给客户端
- 使用
HPACK算法将头部压缩,用哈夫曼编码建立索表,传送索引大大节约了带宽
HTTP 3.0/QUIC
缺点:主要是连接缓慢,服务器只能按顺序响应,如果某个请求花了很长时间,就会出现请求 队头阻塞
HTTP1 和 HTTP2
HTTP2是一个二进制协议,HTTP1是超文本协议,传输的内容都不是一样的HTTP2报头压缩,可以使用HPACK进行头部压缩,HTTP1则不论什么请求都会发送HTTP2服务端推送(Server push),允许服务器预先将网页所需要的资源push到浏览器的内存当中HTTP2遵循多路复用,代替同一域名下的内容,只建立一次连接,HTTP1.x不是,对域名有 6~8 个连接限制
HTTP 请求方法(9 种)
HTTP1.0: GET、POST、HEAD
HTTP1.1: PUT、PATCH、DELETE、OPTIONS、TRACE、CONNECT
HTTP 全称 Hyper Text Transfer Protocol,即超文本传输协议。HTTP 是一个 应用层协议。
HTTP 的报文结构:请求行 + 请求头 + 请求体
Accept 字段与 Content-type 字段:
Accept: 用于客户端向服务器发送报文时表示自己可接收的响应内容类型,如:Accept: text/plain(文本类型)Accept-Charset: 表示可接收的字符集Accept-Encoding: 表示可接受的响应内容的压缩方式Accept-Language: 表示可接受的响应内容语言列表Accept-Datetime: 表示可接受的按照时间来表示的响应内容版本
Content-Type: 字段用于服务器回应时,告诉客户端,本次数据的格式是什么Content-Encoding: 表示服务器返回的数据使用什么压缩格式
Host字段: 用于客户端发送请求时,用来指定服务器的域名。例如:Host: www.baidu.comConnection字段: 最常用于客户端要求服务器使用TCP持久连接,以便其他请求复用keep-aliveContent-Length字段: 表明本次回应的数据长度
HTTP 存在的问题
性能问题
在
HTTP/1.0中,每次发起一个HTTP请求,都需要去建立一次TCP 连接,而且还是串行请求,这使得HTTP在TCP 的连接建立上花费了大量的开销。对于这种问题,HTTP/1.1中提出了长连接的通信方式,也叫持久连接。好处: 在于减少了TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载HTTP/1.1采用了长连接的方式,使得管道(Pipeline)网络传输成为了可能。即在同一个TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。但是 服务器还是按照顺序,先回应第一个请求,完成后再回应第二个请求,以此类推。要是前面的请求回应得特别慢,后面就会有许多请求阻塞着,这就是所谓的【队头阻塞】
总结: HTTP/1.0 或是 HTTP/1.1 性能都不是很完美
安全问题
HTTP的内容是明文传输的,明文数据会经过中间代理服务器、路由器、WIFI热点、通信服务运行商等多个物理节点,如果信息在传输过程中被劫持,传输的内容久完全暴露了,劫持者还可以篡改传输的信息且不被双方察觉,这就是 中间人攻击总结一下,
HTTP在安全方面有以下三个问题:- 使用明文通信,一些重要的内容会被窃听
- 不能验证对方身份,可能是伪造的信息
- 无法验证报文的完整性,有可能被修改
HTTP/2有哪些改进?
- 头部压缩
- 多路复用
- 服务器推送
- 二进制传输
HTTP 的特点和缺点
特点:无连接 (
请求完就断开,不保持连接)、无状态 (每个请求都是独立的)、灵活 (http 协议中头部的 Content-Type 标记,可以传输任意数据类型的数据对象(文本、图像、视频等。比较灵活))、简单快速 (请求访问某个资源时,只需传送请求方法和 URL 就可以了,使用简单)缺点:无状态、不安全 (
明文传输可能被窃听不安全,缺少身份认证也可能遭遇伪装,还有缺少报文完整性验证可能遭到篡改)、明文传输、队头阻塞 (一个TCP连接,同一时刻只能处理一个请求,那么当请求耗时过长时,其他请求就只能阻塞状态)什么是 持久连接/长连接?
http1.0协议采用的是 "请求-应答" 模式,每个请求/应答客户与服务器都要新建一个连接,完成之后立即断开连接(http协议为无连接的协议)http1.1版本支持长连接,即请求头添加Connection: Keep-Alive,使用Keep-Alive模式(又称持久连接,连接复用)建立一个TCP连接后使客户端到服务端的连接持续有效,可以发送/接受多个http请求/响应,当出现对服务器的后续请求时,Keep-Alive功能避免了建立或者重新建立连接- 长连接优缺点?
- 优点
- 减少 CPU 及内存的使用,因为不需要经常建立和关闭连接
- 支持管道化的请求及响应模式
- 减少网络堵塞,因为减少了 TCP 请求
- 减少了后续请求的响应时间,因为不需要等待建立 TCP、握手、挥手、关闭 TCP 的过程
- 发生错误时,也可在不关闭连接的情况下进行错误提示
- 缺点
- 一个长连接建立后,如果一直保持连接,对服务器来说是多么的浪费资源呀,而且长连接时间的长短,直接影响到服务器的并发数
- 还有就是可能造成
队头堵塞
- 优点
- 如何避免长连接资源浪费?
- 客户端请求头声明:
Connection: close,本次通信后就关闭连接 - 服务端配置:如
Nginx,设置keepalive_timeout设置长连接超时时间,keepalive_requests设置长连接请求次数上限
- 客户端请求头声明:
- 长连接优缺点?
什么是 管线化(管道化)?
请求1 -> 响应1 -> 请求2 -> 响应2 -> 请求3 -> 响应3请求1 -> 请求2 -> 请求3 -> 响应1 -> 响应2 -> 响应3管线化: 是在同一个
TCP 连接里发一个请求后不必等其回来就可以继续发请求出去,这可以减少整体的响应时间,但是服务器还是会按照请求的顺序响应请求,所以如果有许多请求,而前面的请求响应很慢,就产生一个著名的问题 队头堵塞管线化的特点:管线化机制通过持久连接完成,在http1.1版本才支持- 只有
GET请求和HEAD请求才可以进行管线化,而POST有所限制 管线化不会影响响应到来的顺序,响应返回的顺序就是请求的顺序- 初次创建连接时不应启动管线化机制,因为服务器不一定支持
http1.1版本的协议
如何解决
HTTP的 队头阻塞 问题?并发连接 (现在的浏览器标准中一个域名并发连接可以有 6~8 个,记住是 6~8 个,不是 6 个(Chrome6 个/Firefox8 个))
域名分片 (一个域名最多可以并发 6~8 个,那咱就多来几个域名,多准备几个二级域名,可以让不同的资源从不同的二域名中获取,而它们都指向同一台服务器,这样能够并发更多的长连接了)
注意:在
HTTP2.0下,可以一瞬间加载出来很多资源,因为支持多路复用,可以在一个 TCP 连接中发送多个请求
3. DNS 解析过程及原理?回源是什么?DNS 劫持听说过吗?
解析域名的查找过程:
浏览器的 DNS 缓存 -> 操作系统的 DNS 缓存 -> 本地域名服务器(递归查询 自己的 DNS 缓存) -> 上级域名服务器(进行迭代查询)【本地域名服务器 -> 根域名服务器(会返回顶级域名的服务器地址); 本地域名服务器 -> 顶级域名服务器(返回权威域名服务器地址,全球 13 台) 】 -》解析到的 IP 地址返回给操作系统,并缓存起来。-》操作系统将 IP 地址返回给浏览器,并缓存起来,供下次使用。
DNS 劫持,是指通过 攻击域名解析服务器(DNS)或 伪造域名解析服务器(DNS)的方法,把目标网站域名解析到错误的 IP 地址从而实现用户无法访问目标网站的目的或者蓄意或恶意要求用户访问指定 IP 地址(网站)的目的。
- 通常来说存在三种情况:
路由器被入侵DNS 服务器被入侵- 运营商流量劫持
4. TCP 和 UDP 区别是什么?
TCP 是一个面向连接的(需要三次握手)、可靠的、基于字节流的传输层协议。而UDP 是一个面向无连接(无需建立连接)的传输层协议。(就这么简单,其它 TCP 的特性也就没有了)。
和
UDP相比,TCP有三大核心特性:面向连接。所谓的连接,指的是客户端和服务器的连接,在双方互相通信之前,
TCP需要三次握手建立连接,而UDP没有相应建立连接的过程。可靠性。
TCP花了非常多的功夫保证连接的可靠,这个可靠性体现在哪些方面呢?一个是有状态,另一个是可控制。TCP 会精准记录哪些数据发送了,哪些数据被对方接收了,哪些没有被接收到,而且保证数据包按序到达,不允许半点差错。这是 有状态。
当意识到
丢包了或者网络环境不佳,TCP 会根据具体情况调整自己的行为,控制自己的发送速度或者重发。这是 可控制。相应的,UDP 就是
无状态,不可控的。- 为什么可靠?
顺序编号(tcp 在传输文件的时候,会将文件拆分为多个 tcp 数据包,会将这些数据包顺序编号)确认机制(当数据包成功的被发送方发送给接收方,接收方会根据 tcp 协议反馈给发送方一个成功接收的 ACK 信号,信号中包含了当前包的序号)超时重传(当发送方发送数据包给接收方时,会为每一个数据包设置一个定时器,当在设定的时间内,发送方仍没有收到接收方的 ACK 信号,会再次发送该数据包,直到收到接收方的 ACK 信号或者连接已断开)校验信息(tcp 首部校验信息较多,udp 首部校验信息较少)
- 为什么可靠?
面向字节流。
UDP的数据传输是基于数据包的,这是因为仅仅只是继承了 IP 层的特性,而TCP为了维护状态,将一个个IP包变成了 字节流。tcp连接过程中出现的延时增加了被攻击的可能,安全性不高,而 udp 不需要连接,安全性较高tcp是可靠的,保证数据传输的正确性,不易丢包,udp是不可靠的,易丢包tcp传输速率较慢,实时性差,udp传输速率较快tcp是字节流模式,udp是数据包模式
UDP的特点:无连接: 不需要握手和挥手就可以直接发送数据不可靠性- 为什么不可靠?
- 传输数据之前不需要先建立连接
- 不保证消息交付,远程主机的传输层在接收到 UDP 报文后,不需要确认
- 不保证将会顺序,不设置包序号、不重排、不会发生队首阻塞
- 不进行拥塞控制,没有内置反馈机制,不重传、无超时
- 为什么不可靠?
支持广播首部开销小: (tcp 建立连接需要耗时,并且 tcp 首部信息太多,每次传输的有用信息较少,实时性差)是面向报文的无拥塞控制
tcp/udp的使用场合?- 对数据可靠性的要求。
tcp适用于可靠性高的场合,udp适用于可靠性低的场合 - 应用的实时性。
tcp有延时较大,udp延时较小 - 网络的可靠性。网络不好的情况下使用
tcp,网络条件好的情况下,使用udp
UDP适用于实时应用,例如:视频会议、直播等。TCP适用于要求可靠性传输的应用,例如:文件传输等。- 对数据可靠性的要求。
5. 如何理解 TCP/IP 五层模型 OSI 七层模型?
TCP/IP 五层模型(应、传、网、数、物)
- 应用层:最高层,提供特定于应用程序的协议,运行在该层的协议有 HTTP、FTP、SSH、WebSocket 等
- 传输层:为两个主机进程通信提供通用的数据传输协议,如 TCP、UDP
- 网络层:负责寻址和路由功能,将数据包发送到特定的计算机,主要协议是 IP 协议,路由器就是在这一层
- 数据链路层:负责将二进制数据包和网络信号相互转换,交换机、网卡就是在这一层(PPP 协议)
- 物理层:主要有接收器、发送器、中继器、光纤电缆等
OSI 七层模型(应、表、会、传、网、数、物)
- 应用层
- 表示层
- 会话层
- 传输层
- 网络层
- 数据链路层
- 物理层
6. 为什么 HTTPS 比 HTTP 安全?HTTPS 是如何保证安全的?
HTTPS 在 HTTP 的基础上增加了加密处理、认证机制和完整性保护,我们可以将 HTTPS = HTTP + 加密 + 认证 + 完整性保护
加密
因为
HTTP使用明文传输,中间会经过多个物理节点,可能会被劫持窃听,针对这一问题,HTTPS采用了加密的方式解决对称加密
就是拥有一个密钥,在内容被进行加密后,需要用同一个密钥对加密内容进行解密,才能看到原本的内容。可以看作我们日常生活中的钥匙。注意:密钥在浏览器和服务器之间传输时,可能被
截取,因此引入非对称加密非对称加密
非对称加密有两把密钥,通常一把叫做公钥,另外一把叫做私钥。用公钥加密的内容必须用私钥才能解开,同样的,私钥加密的内容需要用公钥才能解开。
公钥加密私钥解密(数据加密) 也可用私钥加密公钥解密(签名)改良版非对称加密
通过一组公钥、私钥已经能保证单个方向传输的安全性,那用两组公钥私钥是不是就能保证双向传输都安全了(HTTPS 的加密却没有使用这种方案)。注意:原因是非对称加密算法
非常耗时,特别是加密解密一些较大数据的时候有些力不从心。相反,对称加密就要快很多。混合加密(HTTPS 采用这种方式加密)
思路:我们在传递过程把我们的
对称加密中的密钥用非对称加密的方式去传递“
对称加密+非对称加密”结合的形式来实现对 HTTP 的加密- 客户端生成
会话秘钥就是我们对称加密生成的密钥 - 它用
公钥加密之后进行传递(这个时候被加密的不是数据 是这个会话秘钥 等于把钥匙加密了) 这里的公钥就是非对称加密中的公钥他是由服务器传递过去的(对外公开) - 服务端用
非对称加密的私钥去解密拿到我们的会话秘钥 - 客户端和服务端都能用同一个会话秘钥进行加解密了
- 客户端生成
就算传输过程被攻击者截取到了被加密的会话秘钥 他没有服务器的私钥是无法得到会话秘钥的。上一步我们已经解决了
数据加密的问题 虽然攻击者无法解密数据但是他可以篡改数据 我们怎么知道数据没被动过呢?认证
- 中间人攻击
- 某网站拥有用于
非对称加密的公钥 A、私钥 A; - 浏览器向网站服务器发起请求,服务器把
公钥 A明文给传输浏览器; 中间人劫持到公钥 A,保存下来,把数据包中的公钥 A 替换成自己伪造的公钥 B(它当然也拥有公钥 B 对应的私钥 B’);- 浏览器随机生成一个用于
对称加密的密钥 X,用公钥 B(浏览器不知道公钥被替换了)加密后传给服务器; 中间人劫持后用私钥 B’ 解密得到密钥 X,再用公钥 A 将 X 加密后传给服务器;- 服务器拿到后用
私钥 A解密得到密钥 X。
- 某网站拥有用于
在双方都不会发生异常的情况下,中间人得到了
密钥 X,这其中的根本原因就是浏览器无法确认自己收到的公钥是不是网站的, 如何解决这一问题呢? - 数字证书数字证书(解决
身份伪装问题)如何证明浏览器收到的公钥一定是该网站的公钥?
这里就需要有一个
公信机构给网站颁发一个“身份证”了。网站在使用 HTTPS 前,需要向“CA 机构”申请颁发一份数字证书,数字证书里有证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如同身份证一样,可以证明“该公钥对应该网站”。然而到这里还是有一个问题,
如何保证证书在传输的过程不会被篡改,身份证本身有防伪的技术,那么如何保证证书的防伪呢?数字签名(解决
数据篡改问题)如何保证证书不被篡改?
我们把证书内容生成一份“签名”,比对
证书内容和签名是否一致就能察觉是否被修改,这种技术就称为: 数字签名数字签名的制作过程?
- CA 拥有
非对称加密的私钥和公钥; - CA 对证书明文信息进行
Hash; - 对
Hash后的值用私钥加密,得到数字签名 S;
将明文和数字签名共同组成数字证书,这样一份证书就可以颁发给网站了。- CA 拥有
浏览器得到证书后如何验证这份证书的真实性?
- 拿到服务器发送过来的证书,得到
明文 T,数字签名 S; - 用
CA 机构的公钥对S 解密(由于是浏览器信任的机构,所以浏览器保有 CA 的公钥),得到S‘; - 浏览器用证书说明的
Hash 算法对明文 T进行Hash得到T; - 比较
S是否等于T,等于则代表证书可信。
- 拿到服务器发送过来的证书,得到
浏览器如何得到权威机构的公钥?
上面提到,如何要对服务器发过来的证书进行解密,那么就需要到 CA 的公钥,因为其被 CA 的私钥给加密了。那么浏览器是如何拥有 CA 的公钥呢?
实际上权威机构的公钥并不需要传输,因为权威机构会和主流的浏览器或操作系统合作,将他们的公钥内置在浏览器或操作系统环境中。客户端收到证书之后,只需要从证书中找到权威机构的信息,并从本地环境中找到权威机构的公钥,就能正确解密 CA 公钥。
中间人有可能篡改证书吗?(不可以)
- 中间人攻击
HTTPS 的请求流程
- 客户端向服务器发起 HTTPS 请求,连接到服务器的 443 端口
- 服务器端有一个密钥对,即
公钥和私钥,是用来进行非对称加密使用的,服务器端保存着私钥,不能将其泄露,公钥可以发送给任何人 - 服务器将自己的
公钥包含在权威机构发布的证书中发送给客户端 - 客户端收到服务器端的
证书之后,会对证书进行检查,验证其合法性,如果发现发现证书有问题,那么 HTTPS 传输就无法继续。严格的说,这里应该是验证服务器发送的数字证书的合法性,关于客户端如何验证数字证书的合法性。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,我们将该密钥称之为client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS 中的第一次 HTTP 请求结束; - 客户端会发起 HTTPS 中的第二个 HTTP 请求,将被公钥所加密之后的客户端密钥发送给服务器
- 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是
客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文 - 然后服务器用对称加密的密钥(即客户端密钥)对报文进行加密,并将加密后的报文发送给客户端
- 客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样 HTTPS 中的第二个 HTTP 请求结束,整个 HTTPS 传输完成

7. HTTP 常见的状态码有哪些?适用的场景?
- 1.xx: 信息类
- 2.xx: 成功类
- 【200 OK】:请求成功
- 【204 No Content】: 与 200 基本相同,但响应头没有 body 数据
- 【206 Partial Content】: 应用于 HTTP
分块下载或断点续传。表示响应返回的 body 数据并不是资源的全部,而是其中的一分部
- 3.xx: 重定向
- 【301 Moved Permanently】:永久重定向,说明请求资源不存在了,需改用新的 URL 再次访问
- 【302 Found】:临时重定向,说明请求资源还在,但暂时需要用另一个 URL 来访问
- 4.xx: 客户端错误
- 【400 Bad Request】:表示客户端请求报文有错误
- 【403 Forbidden】: 表示服务器禁止访问资源,并不是客户端请求出错
- 【404 Not Found】:表示请求资源在服务器上不存在或未找到
- 5.xx: 服务端错误
- 【500 Internal Server Error】:与 400 类似,是个笼统的错误码,表示服务器发生了错误
- 【501 No Implement】: 表示客户端请求的功能还不支持
- 【502 Bad Gatwy】:通常服务器作为网关或代理时返回的错误码
- 【503 Service Unavailable】: 表示服务器当前很忙,暂时无法响应
8. 知道 HTTP 的缓存吗?(浏览器强缓存和协商缓存)
强缓存: 是利用 Expires(http1.0)和 Cache-Control(http1.1)这两个字段来控制的,控制资源缓存的时间,在有效期内不会去向服务器请求了,同时存在,优先 Cache-Control
Expires的值为一个绝对时间(由于Expires是依赖于客户端系统时间,当修改了本地时间后,缓存可能会失效)- 给
Cache-Control设置max-age,表示缓存的最长时间是多少秒,是一个相对时间。 Catch-Control的值:public都缓存;private客服端缓存,服务器不缓存;no-cache:表示不进行强缓存,发送HTTP请求,用协商缓存来验证;no-store所有内容都不缓存;s-maxage:这和max-age长得比较像,但是区别: 在于s-maxage是针对代理服务器的缓存时间
协商缓存: 是由服务器来确定缓存资源是否可用,是利用 Last-Modified(http1.0)(表示被请求资源在服务器端的最后一次修改时间)/ If-Modified-Since 和 ETag(每次文件修改后服务端那边会生成一个新的 ETag)/if-None-Match 来控制的,同时存在,优先 ETag
Last-Modified/if-Modified-Since的缺点:(文件有可能在 1s 内修改内容、文件内容修改后又复原)ETag性能上的不足, 只要文件发生改变,ETag就会发生改变.ETag需要服务器通过算法来计算出一个 hash 值缓存位置
Service WorkerService Worker借鉴了Web Worker的 思路,即让JS 运行在主线程之外,由于它脱离了浏览器的窗体,因此无法直接访问 DOM。虽然如此,但它仍然能帮助我们完成很多有用的功能,比如离线缓存、消息推送和网络代理等功能。其中的离线缓存就是Service Worker Cache。Memory CacheDisk CachePush Cache(HTTP2)
浏览器的本地存储主要分为 Cookie、WebStorage 和 IndexedDB, 其中 WebStorage 又可以分为 localStorage 和 sessionStorage。
9. 前端错误的分类有哪些?
- 前端错误类型:
SyntaxError(语法错误)ReferenceError(引用错误)TypeError(类型错误)RangeError(范围越界错误)
- 前端错误分类:
- 代码执行的错误
- 资源加载的错误
- 前端错误捕获:
- try...catch
能捕获
同步运行时错误。不能捕获语法错误、异步任务错误、promise、资源加载错误等 - window.onerror 能捕获所有同步错误、普通的异步错误。不能捕获语法、async 任务、promise 错误和资源加载错误等(例如:iframe)
- window.addEventListener('error', function() {}) 可捕获资源加载错误(如果资源加载错误,说明跨域,添加 crossorigin)
- window.addEventListener('unhandledrejection', function() {})
捕获 promise 错误(没有写
catch的Promise中抛出的错误无法被onerror或try-catch捕获到。为了防止有漏掉的 Promise 异常,建议在全局增加一个对unhandledrejection的监听,用来全局监听Uncaught Promise Error) - Vue 项目异常:Vue.config.errorHandler = (err, vm, info) => {}
- 崩溃和卡顿:利用
window对象的load和beforeunload事件
- try...catch
能捕获
- 总结:
- 可疑区域使用:
Try...Catch - 全局监控 JS 异常使用:
window.onerror - 全局监控静态资源异常使用:
window.addEventListener - 捕获没有 catch 的 Promise 异常使用:
unhandledrejection Vue errorHandler和React componentDidCatch- 监控网页崩溃和卡顿使用:
window对象的loader和beforeunload - 跨域:添加
crossOrigin
- 可疑区域使用:
- 上报方式有哪些:
XMLHttpRequest有跨域限制,携带 cookie 问题;上报请求可能会阻塞业务;请求容易丢失Image可跨域、get 请求,大小限制- SendBean
10. 说说为什么前端会有跨域?如何解决跨域?知道 option 请求吗?
不同域之间相互请求资源,称为”跨域“;浏览器的 同源策略(同源:url 是由协议、域名、端口和路径等组成。如果两个路径的协议、域名、端口都相同则表示再同一个域上)
在浏览器上 script、img、link、iframe 等标签都可以加载跨域资源 且不受同源限制
非同源限制:
- 无法读取非同源网页的 Cookie、LocalStorage、IndexedDB
- 无法接触非同源网页的 DOM
- 无法向非同源地址发起 ajax 请求
解决跨域的方式:
- 设置 document.domain 解决无法读取非同源网页的 Cookie 问题
浏览器是通过
document.domain属性来检查两个页面是否同源,因此只要通过设置相同的document.domain,两个页面就可以共享 Cookie。缺点:此方案仅限主域相同,子域不同的跨域应用场景
- JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本 IE),
缺点:是只支持
get 请求, 需要后台配合,将返回结果包装成callback(res)的形式。原理是利用script元素的跨域能力核心思想:网页通过添加一个
script元素,向服务器请求JSON数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来原生 js 实现【请求地址后面添加?callback="xxx",然后在 script 中添加 xxx 方法其参数返回结果】jQuery 的 ajax【dataType: 'jsonp', 请求方式为 jsonp;jsonpCallback: 'handleCallback' 自定义回调函数】扩展:
script的src和img的src跨域的区别?
原理上都是利用标签的
src可绕过同源限制,跨域请求的特点;区别在于:img 只能单向发送 get 请求,不可访问响应内容(只是展现),而 script 可对其进行解析- 如果黑客植入
script脚本通过jsonp的方式对服务器进行攻击,怎么办?
可以通过页面设置的
内容安全协议 csp进行防范- 为什么
jsonp只支持get请求?
JSONP是一种【请求一段JS 脚本,把执行这段脚本的结果当做数据】的玩法。JSONP的实现原理就是document.createElement('script')生成一个script 标签,然后插body里而已。在这里根本没有设置请求格式的余地). 所以jsonp不会对服务器端代码或者内容做更改
H5 提供的 postMessage
postMessage事件发送消息,message事件接受消息跨域资源共享 CORS【常用】
浏览器将
CORS请求分成两类:简单请求和非简单请求;当发出简单请求,只需要在头信息之中增加一个Origin 字段。当发出CORS非简单请求,会在正式通信之前,增加一次OPTIONS查询请求,称为"预检"请求(preflight)。设置响应头的
Access-Control-Allow-Origin: *- 扩展:简单请求同时满足的三个条件?
- 请求方式只能是:
GET、POST、HEAD HTTP请求头限制这几种字段:Accept、Accept-Language、Content-Language、Content-Type、Last-Event-IDContent-type只能取:application/x-www-form-urlencoded(是 Jquery 的 Ajax 请求默认方式)、multipart/form-data、text/plain
- 请求方式只能是:
预检请求(
preflight):浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。重点:服务端如何避免每次都发出预检请求?(
缓存)Access-Control-Max-Age该字段可选,用来指定本次预检请求的有效期,单位为秒。在有效期间,不用发出另一条预检请求(全局和局部方式)【常用】@CrossOrigin注解,可细粒度精确到单个请求级别
- 扩展:简单请求同时满足的三个条件?
window.name
name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的name值(2MB)vue中proxy配置本地代理扩展:说说
Webpack Proxy工作原理?proxy工作原理实质上是利用 http-proxy-middleware 这个http代理中间件,实现请求转发给其他服务器H5 中的 websocket
Nginx 代理
扩展:跨域请求如何携带 Cookie?
- 前端请求时在
request对象中配置:withCredentials: true - 服务端在
response的header中配置:Access-Control-Allow-Origin: "http://xxx.com" - 服务器在
response的header中配置:Access-Control-Allow-Credentials: true
11. TCP 三次握手 & 四次挥手(短连接 & 长连接)?
三次握手的主要作用,需要确认双方的两样能力: 发送的能力和接收的能力
从最开始双方都处于 CLOSED 状态。然后服务端开始监听某个端口,进入了 LISTEN 状态。
- 客户端给服务端发一个
SYN报文,并指明客户端的初始化序列号seq。此时客户端处于SYN_SEND状态。 - 服务端接收到,返回
SYN和ACK(对应客户端发来的 SYN),确认号ack,自己变成了SYN-REVD - 之后客户端再发送 确认应答
ACK报文 给服务端,自己变成了ESTABLISHED状态;服务端收到ACK之后,也变成了ESTABLISHED状态。
为什么不是两次?
根本原因:
无法确认客户端的接收能力。- 第一次握手:客户端发送网络包,服务端收到了。服务端就能得出结论:
客户端的发送能力、服务端的接收能力是正常的 - 第二次握手:服务端发包,客户端收到了。客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。注意:此时服务器并不能确认客户端的
接收能力是否正常 - 第三次握手:客户端发包,服务端收到了。服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
- 第一次握手:客户端发送网络包,服务端收到了。服务端就能得出结论:
为什么不是四次?
三次握手的目的: 是确认双方
发送和接收的能力,四次也可以。没必要什么是半连接队列?
三次握手前,服务端的状态从
CLOSED变为LISTEN, 同时在内部创建了两个队列:半连接队列和全连接队列,即SYN 队列和ACCEPT 队列。半连接队列: 当客户端发送
SYN到服务端,服务端收到以后回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就被推入了SYN 队列,也就是半连接队列。全连接队列: 就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现
丢包现象。补充一点 关于
SYN-ACK重传次数的问题:服务器发送完
SYN-ACK 包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。三次握手过程中可以携带数据么?
第三次握手的时候,可以携带。前两次握手不能携带数据。(假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的
SYN 报文中放入大量的数据。这会让服务器花费很多时间、内存空间来接收这些报文。原因就是会让服务器更加容易受到攻击了)SYN 攻击是什么?SYN 攻击: 就是
Client在短时间内伪造大量不存在的IP 地址,并向Server不断地发送SYN 包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN 包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的DoS/DDoS 攻击。在
Linux/Unix上可以使用系统自带的netstats命令来检测SYN 攻击。netstat -n -p TCP | grep SYN_RECV- 常见的防御
SYN 攻击的方法有如下几种:- 缩短超时(
SYN Timeout)时间 - 增加最大半连接数
- 过滤网关防护
SYN cookies技术
- 缩短超时(
- 常见的防御
TCP的半关闭(half-close)所谓的半关闭,其实就是
TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
刚开始双方处于 ESTABLISHED 状态
客户端要断开了,向服务器发送
FIN 报文,发送后客户端变成了FIN-WAIT-1状态。 注意, 这时候客户端同时也变成了half-close(半关闭)状态,即无法向服务端发送报文,只能接收。- 关闭
TCP 连接的挥手,客户端和服务端都可以发起关闭操作,以客户端发起为例:- 浏览器先发送
FIN 报文、Seq初始化序列号给服务器,并停止发送数据,但仍可以接受服务端响应的数据 - 服务器收到后,发送
ACK=浏览器序列号+1给浏览器,表明收到 - 服务器数据都发完了,给浏览器发送
FIN 报文、Seq序列号给浏览器 - 浏览器收到后,发送
ACK=服务器序列号+1给服务器,表明收到
- 浏览器先发送
- 关闭
为什么是
四次挥手而不是三次?因为服务端在接收到
FIN, 往往不会立即返回FIN, 必须等到服务端所有的报文都发送完毕了,才能发FIN。因此先发一个ACK表示已经收到客户端的FIN,延迟一段时间才发FIN。这就造成了四次挥手。- 如果是
三次挥手会有什么问题?
(等于说服务端将
ACK和FIN的发送合并为一次挥手,这个时候长时间的延迟可能会导致客户端误以为FIN没有到达客户端,从而让客户端不断的重发FIN。)- 如果是
等待
2MSL的意义(为什么要等一段时间再关闭,不等不行吗?)这是为了防止发送给服务器的确认报文段
丢失或者出错,从而导致服务端不能正常关闭。等待时间是2MSL,这也是报文在网络上的最大生存时间,超过这个时间就会被丢弃。RFC793中规定MSL为 2 分钟,如果超过这个时间,那么主动关闭者就会发送一个RST状态位的包,表示重置连接,这时候被关闭者就知道对方已经关闭了连接。
12. 知道第三方 Cookie 吗?
cookie由哪些部分组成:Name: 这个属性就表示cookie的名字,每个cookie的名字都是唯一的Value: 这个属性表示cookie的值Domain: 就是cookie所在的域名,如果没有设置domain的话,那么cookie会自动绑定到执行语句的当前域Path: 这个属性的默认值是/,匹配的是路由,这里匹配的是路由的意思就是比如你的域名是www.xxx.xyz,那么路由如果是www.xxx.xyz/auth/,那么实际上cookie绑定的是这个/authMax-age: 这个属性是http1.1新增的属性,用来替代expires的,单位是秒,用来表示cookie在多少秒之后会失效Secure: 因为http是无状态协议,而且http在传输数据的过程中是以明文传输的,因此很容易遭到第三方网站的窃取,如果我们使用secure的话,就能够确保cookie是在https协议下进行传输的,但是这不代表会将cookie加密HttpOnly: 只能通过HTTP协议传输,不能通过JS 访问。这个属性表示不能够被js 脚本访问,因为js能够通过document.cookie来获取cookie,所以使用HttpOnly就能够阻止这种情况,在一定程度上防止xss 攻击,也就是跨站脚本攻击SameSite: 用于限制第三方网站的cookie发送机制(cookie每次随着请求会自动发送到服务器去的,这就给了其他站点发起CSRF 攻击和用户追踪的机会) 具体如下:Strict: 最严格的模式,完全禁止跨站点请求时携带cookie,设置为strict之后,跨站行为都不会再携带cookieLax: 相对strict 模式会宽松一点儿,允许导航到三方网站时携带cookie,即a 标签跳转,form 表单的 get 提交,以及link 标签的 prerenderNone: 使用None显示的关闭SameSite模式控制,但是需要注意的是还需要加上secure,即cookie只会在HTTPS中发送,如果只是设置了SameSite=None是没有效果的
Cookie的分类:第一方 Cookie 和 第三方 Cookie,这两类
Cookie都是网站保存在用户电脑上的一个文件,它们都由某个特定的域创建,并且只能被这个域访问第一方 Cookie是由地址栏中列出的网站域设置的Cookie,而第三方 Cookie来自在网页上嵌入广告或图片等项的其他域来源。都是网站在客户端上存放的一小块数据。他们都由某个域存放,只能被这个域访问。他们的区别其实并不是技术上的区别,而是使用方式上的区别。
Cookie的特性:- 生命周期:
Expires(过期时间) 和Max-Age(单位秒)设置 - 作用域:
Domain和Path设置。注意:/表示域名下的任何路径都允许使用Cookie - 安全相关
- 如果带上
Secure,说明只能通过HTTPS传输cookie - 如果
cookie字段带上HttpOnly,说明只能通过HTTP协议传输,不能通过JS 访问。也是预防XSS 攻击重要手段 SameSite属性有Strict、Lax、None(默认)。也是预防CSRF 攻击的重要手段
- 如果带上
- 生命周期:
Cookie的缺点:- 容量缺陷:
Cookie的体积上限只有4KB,只能用来存储少量的信息 - 性能缺陷:
Cookie紧跟域名,不管域名下面的某一个地址需不需要这个Cookie,请求都会携带上完整的Cookie,这样随着请求数的增多,其实会造成巨大的性能浪费的,因为请求携带了很多不必要的内容。但可以通过Domain和Path指定作用域来解决。 - 安全缺陷。由于
Cookie以纯文本的形式在浏览器和服务器中传递,很容易被非法用户截获,然后进行一系列的篡改,在Cookie的有效期内重新发送给服务器,这是相当危险的。另外,在HttpOnly为false的情况下,Cookie信息能直接通过JS 脚本来读取。
- 容量缺陷:
13. CSRF 和 XSS 、SSRF 的攻击原理 与防御措施?
CSRF(Cross-site request forgery):跨站请求伪造: 是一种劫持受信任用户向服务器发送非预期请求的攻击方式
CSRF的攻击原理

从上图可以看出,要完成一次 CSRF 攻击,受害者必须满足 两个必要的条件:
- 登录受信任
网站 A,并在本地生成Cookie。(如果用户没有登录网站 A,那么网站 B在诱导的时候,请求网站 A的api 接口时,会提示你登录) - 在不登出
A的情况下,访问危险网站B(其实是利用了 ∂网站 A的漏洞)
温馨提示一下:cookie 保证了用户可以处于登录状态,但网站 B 其实拿不到 cookie
CSRF如何防御方法一、
Token验证:(用的最多)服务器发送给客户端一个
token;客户端提交的表单中带着这个token。如果这个token不合法,那么服务器拒绝这个请求。方法二、
隐藏令牌:把
token 隐藏在http的head头中。方法二和方法一有点像,本质上没有太大区别,只是使用方式上有区别。方法三、
Referer验证:Referer指的是页面请求来源。意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截。
XSS(Cross Site Scripting):跨域脚本攻击: 是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式
XSS的攻击原理XSS 攻击的核心原理是:不需要你做任何的登录认证,它会通过合法的操作(比如在url 中输入、在评论框中输入),向你的页面注入脚本(可能是js、html 代码块等)。导致:盗用Cookie、破坏页面的正常结构,插入广告等恶意内容、D-doss 攻击XSS的攻击方式反射型
发出请求时,
XSS 代码出现在url中,作为输入提交到服务器端,服务器端解析后响应,XSS 代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,所以叫反射型 XSS存储型
存储型 XSS和反射型 XSS的差别在于,提交的代码会存储在服务器端(数据库、内存、文件系统等),下次请求时目标页面时不用再提交XSS 代码
XSS的防范措施(encode+过滤)方法一、
编码对用户输入的数据进行
HTML Entity编码;把字符转换成 转义字符方法二、
过滤移除用户输入的和事件相关的属性。如 onerror 可以自动触发攻击,还有 onclick 等。(总而言之,过滤掉一些不安全的内容) 移除用户输入的
Style 节点、Script 节点、Iframe 节点。(尤其是 Script 节点,它可是支持跨域的呀,一定要移除)方法三、
校正避免直接对
HTML Entity进行解码; 使用DOM Parse转换,校正不配对的DOM标签
CSRF和XSS的区别:- CSRF:需要用户先登录
网站 A,获取cookie; XSS:不需要登录 CSRF:是利用网站 A本身的漏洞,去请求网站 A的api;XSS:是向网站 A注入JS 代码,然后执行 JS里的代码,篡改网站 A的内容
- CSRF:需要用户先登录
SSRF
扩展:v-html 的弊端?(利用 innerHTML)
- 可能会导致
xss 攻击 v-html会替换掉标签内部的子元素
14. V8 中执行一段 JS 代码的整个过程
- 首先通过
词法分析和语法分析生成AST- 词法分析 即
分词,它的工作就是将一行行的代码分解成一个个token。 - 语法分析 ,将生成的这些
token数据,根据一定的语法规则转化为AST。
- 词法分析 即
- 将
AST转换为字节码 - 由
解释器逐行执行字节码,遇到热点代码启动编译器进行编译,生成对应的机器码, 以优化执行效率 (现在不用一次性将全部的字节码都转换成机器码,而是通过解释器来逐行执行字节码,省去了生成二进制文件的操作,这样就大大降低了内存的压力。)
注意:因为机器码相比字节码的体积太大,引发了严重的内存占用问题。机器只认识机器码
JS 运行可以分为 编译阶段 和 执行阶段
函数体内 的
编译四步曲,发生在函数执行之前:- 创建
AO对象, (activation object) - 找
形参和变量声明,将形参和变量声明作为AO对象的属性名,值为undefined - 将
实参和形参相统一 - 在函数体里找函数声明,将函数名作为
AO对象的属性名,值赋予函数体
- 创建
全局下 的
编译三步曲,发生在代码最前面:- 创建
GO对象 - 找变量声明,将变量声明作为
GO对象的属性名,值赋予undefined - 找全局里的函数声明,将函数名作为
GO对象的属性名,值赋予函数体
- 创建
14. 从输入 URL 到页面展示经历了什么?
总体流程如下:
URL 解析 完整的 URL:
协议 + 主机 + 端口 + 路径 + 参数 + 锚点。如果为非 url 结构的字符串,交给浏览器默认引擎去搜索改字符串;若为 url 结构的字符串,浏览器主进程会交给 网络进程 ,开始干活。- encodeURI 和 encodeURIComponent 的区别?
encodeURI 是编码
整个URL,而 encodeURIComponent 编码的是参数部分
- encodeURI 和 encodeURIComponent 的区别?
encodeURI 是编码
检查资源缓存 在有效期内的缓存资源直接使用,称之为
强缓存。返回 200,size 为 memory cache(资源从内存中取出)和 disk cache(资源从磁盘中取出)。当超过有效期的,则携带缓存的资源标识向服务器发起请求。返回 304,走协商缓存;返回 200,向服务器发起请求,将结果缓存起来,为下一次使用 通常来说:刷新页面会使用内存缓存; 关闭后重新打开会使用磁盘缓存DNS 解析:将域名解析成 IP 地址 如果没有成功使用本地缓存,则需要发起网络请求,发起之前要做 DNS 解析,会依次搜索:
浏览器DNS缓存 -> 操作系统DNS缓存 -> 路由器DNS缓存 -> 服务商DNS服务器查询 -> 全球13台根域名服务器查询解析域名的查找过程:浏览器的 DNS 缓存 -> 操作系统的 DNS 缓存 -> 本地域名服务器(递归查询自己的 DNS 缓存) -> 上级域名服务器(进行迭代查询)【本地域名服务器 -> 根域名服务器(会返回顶级域名的服务器地址); 本地域名服务器 -> 顶级域名服务器(返回权威域名服务器地址,全球 13 台) 】 -》解析到的 IP 地址返回给操作系统,并缓存起来。-》操作系统将 IP 地址返回给浏览器,并缓存起来,供下次使用。
为了节约时间,可以在 HTML 头部做 DNS 的预解析:
<!-- 在HTTPS下开启 --> <meta http-equiv="x-dns-prefetch-control" content="on" /> <link rel="dns-prefetch" href="http://www.baidu.com" />为了保证响应的及时,DNS 解析使用的是 UDP 协议。浏览器根据自定义的规则,提前去解析后面可能用到的域名,来加速网站的访问速度。
注意:a 标签的 href 是可以在 chrome。firefox 包括高版本的 IE,但是在 HTTPS 下面不起作用,需要 meta 来强制开启功能。
TCP 连接:TCP 三次握手
三次握手过程:
- 客户端发送一个带 SYN=1, Seq=X 的数据包到服务器(第一次握手,由浏览器发起,告诉服务器,我要发送请求了)
- 服务器返回一个带 SYN=1, Ack=X+1, Seq=Y 的响应包确认信息给浏览器(第二次握手,由服务器发起,告诉浏览器我准备好了,你发吧)
- 客户端回传一个带 ACK=Y+1, Seq=Z 的数据包,代表”握手结束“(第三次握手,由浏览器发起,告诉浏览器,我马上就发了,准备接受吧)
扩展:为啥要三次握手?目的:为了防止已失效的连接请求报文突然又传送到服务器,因而产生错误。
发送 HTTP 请求
服务器处理请求并返回 HTTP 报文
浏览器解析并渲染页面
断开 TCP 连接:TCP 四次挥手
- 四次挥手过程:
- 主动方发送一个 Fin=1 结束标志位,Ack=Z 组成的报文,并发送 Seq=X 序列号。并进入到 FIN_WAIT_1 状态(第一次挥手:由浏览器发起的,发送给服务器,我请求报文发送完了,你准备关闭吧)
- 被动方发送 ACK=X+1 确认标志位报文,并发送 Seq=Z 的序列号。表示同意关闭请求。此时主机发起方进入 FIN_WAIT_2 阶段。(第二次挥手:由服务器发起的,告诉浏览器,我请求报文接受完了,我准备关闭了,你也准备吧)
- 被动方发送 Fin=1 结束标志位,Ack=X 组成的报文,并发送 Seq=Y 的序列号。进入 LAST_ACK 状态(第三次挥手:由服务器发起,告诉浏览器,我响应报文发送完了,你准备关闭吧)
- 发送方发送 ACK=Y 确认标志位报文,并发送 Seq=Z 的序列号。进入等待 TIME_WAIT 状态。被动方收到发起方的报文段以后关闭连接。发起方等待一定时间未收到回复,则正常关闭。(第四次挥手:由浏览器发起,告诉服务器,我响应报文接受完了,我准备关闭了,你也准备吧)
- 四次挥手过程:
15. 说说浏览器渲染原理?
整个渲染流程,从 HTML 到 DOM、样式计算、布局、图层、绘制、光栅化、合成和显示
解析
HTML,生成DOM树。解析CSS,生成CSSOM树浏览器从磁盘或网络读取
HTML的原始字节,并根据文件的指定编码(例如UTF-8)将它们转换成字符串。DOM 树构建步骤:
字节数据=》字符串=》Token=>Node(节点对象) =》DOM生成节点对象并构建
DOM,每个Token被生成后,会立刻消耗这个Token创建出节点对象。注意:带有结束标签标识的 Token 不会创建节点对象。关于
CSS 样式,它的来源一般是三种:link 标签引用style 标签中的样式- 元素的
内嵌 style 属性
格式化样式表:首先,浏览器是无法直接识别 CSS 样式文本的,因此渲染引擎接收到
CSS 文本之后第一件事情就是将其转化为一个结构化的对象,即styleSheets标准化样式属性:有一些
CSS 样式的数值并不容易被渲染引擎所理解,因此需要在计算样式之前将它们标准化,如em->px,red->#ff0000,bold->700等等。计算每个节点的具体样式:样式已经被
格式化和标准化, 接下来就可以计算每个节点的具体样式信息了。计算的方式也并不复杂,主要就是两个规则: 继承和层叠。- 每个子节点都会默认
继承父节点的样式属性,如果父节点中没有找到,就会采用浏览器默认样式,也叫UserAgent 样式。这就是 继承规则 - 然后是
层叠规则,CSS最大的特点在于它的层叠性,也就是最终的样式取决于各个属性共同作用的效果 注意:在计算完样式之后,所有的样式值会被挂在到window.getComputedStyle当中,也就是可以通过JS来获取计算后的样式
- 每个子节点都会默认
将
DOM 树和CSS 树结合,生成渲染/布局树(Render Tree) Chrome 团队已经做了大量的重构,已经没有生成Render Tree的过程了。而布局树的信息已经非常完善,完全拥有Render Tree的功能。布局树生成的大致工作如下:- 遍历生成的
DOM 树节点,并把他们添加到布局树中。 - 计算布局树节点的坐标位置。
- 遍历生成的
Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置、大小)Painting(重绘):根据渲染树以及回流得到节点的几何信息,从而得到节点的绝对像素Display:将像素发送给GPU。展示在页面上
注意:渲染树只包含可见的节点
扩展:为了构建渲染树,浏览器主要完成了以下工作:
从
DOM 树的根节点开始遍历每个可见节点对于每个可见的节点,找到
CSSOM 树中对于的规则,并应用它们根据每个可见节点以及其对应的样式,组合生成渲染树
- 不可见的节点包括:
- 一些不会渲染输出的节点:如:
script、link、meta等 - 一些通过
CSS进行隐藏的节点:如:display: none
- 一些不会渲染输出的节点:如:
- 不可见的节点包括:
注意:利用 visible 和 opacity 隐藏节点,还是会显示在渲染树上的
分层:渲染引擎给页面分了很多图层,这些图层按照一定顺序叠加在一起,就形成了最终的页面。完成图层树的构建后,渲染引擎会对图层树中的每个图层进行绘制,为图层绘制。然后进行栅格化(raster)操作(绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的),最后合成与显示。
扩展:CSS 加载会阻塞页面显示吗?
- css 加载不会阻塞 DOM 树的解析
- css 加载会阻塞 DOM 树的渲染
- css 加载会阻塞后面 js 语句的执行
so, 为了防止 css 阻塞,引起页面白屏,可以提高页面加载速度:
- 使用 cdn
- 对 css 进行压缩
- 合理利用缓存
- 减少 http 请求,将多个 css 文件合并
16. 前端需要注意哪些 SEO?
- 合理的
title、description、keywords - 语义化
HTML 代码 - 重要内容
HTML 代码放在前面(搜索引擎抓取HTML顺序是从上到下),不要用js 输出(爬虫不会执行 js) - 少用
iframe(搜索引擎不会抓取 `iframe 中的内容) - 非装饰性图片必须加
alt - 提高网站速度(网站速度是搜索引擎排序的一个重要指标)
17. 什么是堆?什么是栈?它们之间有什么区别和联系?
堆和栈的概念存在于数据结构中和操作系统内存中。
- 在数据结构中,栈中数据的存取方式为
先进后出。而堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。完全 二叉树是堆的一种实现方式。 - 在操作系统中,内存被分为
栈区和堆区。栈区内存由编译器自动分 配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。堆区内存一般由程序员分配释放,若程序员不释放,程序结束时可能由垃圾回收机制回收。