浏览器面试总结

80 阅读16分钟

输入URL地址到浏览器完成渲染的整个过程

简单版

1.浏览器地址栏输入URL地址,回车

2.查找缓存:浏览器先查看浏览器缓存-系统缓存-路由缓存中是否有该地址页面,如果有则显示页面内容。如果没有则进行下一步。

3.DNS域名解析:浏览器向DNS服务器发起请求,解析该URL中的域名对应的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议

4.建立TCP连接:解析出IP地址后,根据IP地址和默认80端口,和服务器建立TCP连接

5.发起HTTP请求:浏览器发起读取文件的HTTP请求,,该请求报文作为TCP三次握手的第三次数据发送给服务器

6.服务器响应请求并返回结果:服务器对浏览器请求做出响应,并把对应的html文件发送给浏览器

7.关闭TCP连接:通过四次挥手释放TCP连接

8.浏览器渲染:客户端(浏览器)解析HTML内容并渲染出来,浏览器接收到数据包后的解析流程为

  • 构建DOM树:词法分析然后解析成DOM树(dom tree),是由dom元素及属性节点组成,树的根是document对象

  • 构建CSS规则树:生成CSS规则树(CSS Rule Tree)

  • 构建render树:Web浏览器将DOM和CSSOM结合,并构建出渲染树(render tree)

  • 布局(Layout):计算出每个节点在屏幕中的位置

  • 绘制(Painting):即遍历render树,并使用UI后端层绘制每个节点。

9,JS引擎解析过程:调用JS引擎执行JS代码(JS的解释阶段,预处理阶段,执行阶段生成执行上下文,VO,作用域链、回收机制等等)

高级版

  • 浏览器输入URL 输入URL,按下回车,就进入应用层往下走,浏览器会开一个线程处理,对URL解析

  • 应用层DNS解析域名 DNS解析就是对域名或IP解析

    • 首先查看浏览器DNS缓存
    • 没有就查询计算机本地DNS缓存
    • 还没有就询问递归式DNS服务器
  • 应用层客户端发送HTTP请求 IP地址有了,客户端就会发送一个HTTP请求,HTTP请求分为请求报头和请求主体

    • 请求报头包含:请求方法(POST,GET等),协议版本号,请求头部方法(Accept、Cache-Control...)
    • 请求主体:客户端发送给服务器或者服务器返回给客户端的内容
  • 传输层TCP传输报文 客户端在传输层开始和服务器通过三次握手建立TCP/IP连接

  • 网络层IP协议查询MAC地址 网络层IP协议会查询MAC地址进行数据包的传输

  • 数据到达数据链路层 找到对方的MAC地址后,会将数据发送到数据链路层传输,到此客户端发送请求阶段就结束了

  • 服务器接收数据 服务器在数据链路层接收到数据包,在通过相反的方式将数据一层一层的还原回应用层 请求到后台服务器,会有验证(安全验证、跨域验证等),验证未通过就直接返回相应的HTTP报文,验证通过,就执行对应的操作 如果浏览器访问过,且缓存上有对应的资源,就会与服务器最后修改的时间对比,一致就返回304,告诉浏览器可使用本地缓存

  • 服务器响应请求 服务器接收到客户端发送的HTTP请求后,会查找客户端请求的资源,并返回响应报文。

  • 服务器返回相应文件 请求成功后,服务器会返回相应的网页,浏览器接收到响应成功的报文后便开始下载网页,网络通信结束

  • 解析HTML构建DOM Tree

  • 解析CSS构建CSSOM Tree

  • 构建渲染树(Render Tree) 将DOM树和CSSOM树合并成渲染树,渲染树只包含渲染网页所需的节点,然后用于计算每个可见元素的布局,并输出给绘制流程,将像素渲染在屏幕上。

  • 布局

  • 绘制

  • 合成

简洁回答

  • 首先,客户端浏览器输入URL,由于是域名,应用层DNS开始解析域名

  • 接着,应用层客户端发送一个HTTP请求,把拿到的应用层HTTP请求报文数据分割编号,为了方便安全的传输,传输层会通过TCP三次握手建立TCP/IP链接

  • 建立连接后 网络层 IP协议会查询服务器 MAC地址 也就是物理地址进行数据包的传输

  • 找到对方的 MAC地址 后,将数据发送到 数据链路层传输,到此客户端发送请求阶段结束

  • 接收端的服务器在 数据链路层 接收到数据包,再通过相反的方式将数据一层一层的还原回 应用层

  • 服务器接收到客户端发送的HTTP请求后,会查找客户端请求的资源,并返回响应报文

  • 请求成功后,服务器会返回相应的网页,浏览器接收到响应成功的报文后便开始下载网页,至此,网络通信结束

  • 浏览器拿到网页文件后,首先根据顶部定义的DTD类型进行对应解析方式,网页解析会交给内部GUI渲染线程处理

  • 接着构建DOM树和CSSOM树,过程中,如果遇到节点是 JS ,就会调用 JS引擎 对 JS代码进行解释执行,此时由于 JS引擎GUI渲染线程 互斥,GUI渲染线程 会被挂起,渲染过程停止,如果 JS 代码的运行中对DOM树进行了修改,那么DOM构建要从新开始,然后DOM树和CSSOM树构建为渲染树

  • 然后进入布局阶段,计算渲染树节点在设备视口内的确切位置和大小

  • 再接着将渲染树中每个节点转换成屏幕上的实际像素,也就是绘制阶段

  • 最后的合成阶段浏览器会将各层信息发送给GPU,GPU将各层合成,显示在屏幕上

详细解析

针对第二项解析

1.HTTP缓存:强缓存 2.HTTP缓存:协商缓存

针对三次握手

  • 1.第一次握手:

客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;(由浏览器发起,告诉服务器我要发送请求了)

  • 2. 第二次握手:

服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(Seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;(由服务器发起,告诉浏览器我准备接受了,你赶快发送)

  • 3. 第三次握手:

客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。(由浏览器发送,告诉服务器,我马上发,准备接受)

为啥需要三次握手??

三次握手”的目的是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

三次握手过程中可以携带数据么?

第一次、第二次握手不可以携带数据,因为一握、二握还没有建立连接,会让服务器容易受到攻击。 三次握手,客户端处于ESTABLISHED(已建立连接状态),可以携带数据

发送HTTP请求

发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议中发送到服务器指定端口 请求报文由请求行,请求报头,请求正文组成

服务器处理请求并返回HTTP报文

状态码、响应报头、响应报文

浏览器解析渲染页面

1.解析HTML形成DOM树 2.解析CSS形成CSSOM树 3.合并DOM树和CSSOM树形成渲染树 4.浏览器开始渲染并绘制页面(回流和重绘)

针对四次挥手

1.第一次挥手:

客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1(终止等待1)状态。

2.第二次挥手:

服务端收到FIN包后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务端进入CLOSE-WAIT状态。客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文。

3.第三次挥手:

服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端就进入了LAST_ACK(最后确认)状态,等待客户端的确认。

4.第四次挥手:

客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务器,确认序号为收到序号+1,服务端进入CLOSED状态,完成四次挥手。

简单理解记忆:(FIN:finish,ACK:acknowledge)

  • 客户端------FIN------》服务端
  • 服务端------ACK------》客户端
  • 服务端------FIN------》客户端
  • 客户端------ACK------》服务端

浏览器兼容问题

不同的浏览器,内核和实现方式不同,同一份页面在显示和功能上会存在差异或者错误的情况。

常见的兼容性问题

1、盒模型差异

盒模型是指元素的尺寸由内容、内边距、边框和外边距组成。在标准盒模型中,元素的宽度和高度只包括内容的部分,而在IE盒模型中,元素的宽度和高度还包括内边距和边框的部分。为了解决这个问题,可以使用CSS的box-sizing属性来指定盒模型的类型,将其设置为border-box即可。box-sizing:border-box

2、浮动布局问题

在使用浮动布局时,可能会出现浮动元素高度塌陷或者浮动元素重叠的问题。为了解决这个问题,可以使用清除浮动的方法,例如在浮动元素的父容器中添加一个带有clear:both样式的空元素。

<div class="clearfix"></div>
<style>
.clearfix{
  clear:both
}
</style>

3、文字换行问题

不同浏览器对于文字的换行方式可能存在差异,导致文字在不同浏览器中显示不一致。为了解决这个问题,可以使用CSS的word-wrap属性来控制文字的换行方式。word-wrap:break-word

4、行内元素间隙问题

在某些浏览器中,行内元素之间可能存在一些间隙,导致布局不一致。为了解决这个问题,可以使用CSS的font-size: 0属性来消除行内元素之间的间隙。font-size:0

5、CSS3属性兼容问题

CSS3中的一些新属性在不同浏览器中的支持程度可能不一样,导致样式的显示效果不一致。为了解决这个问题,可以使用CSS前缀来指定不同浏览器的私有属性。

-webkit-border-radius:5px;
-moz-border-radius:5px;
border-radius:5px

浏览器跨域

原因

浏览器的同源策略,即浏览器规定必须协议域名端口保持一致时,才算同源。

如何解决跨域

1、跨域资源共享(CORS)

浏览器将 CORS请求分成两类:简单请求非简单请求

简单请求(浏览器直接发出CORS请求【在头信息中增加一个Origin字段】)

满足两个条件,就是简单请求

  • 请求方法是三种方法之一:head、get、post
  • 2、http的头部信息不超出以下几种字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type
非简单请求(先发出一个预检请求,预检请求方法是OPTIONS,[用来获知服务器是否允许该实际请求])

满足条件:

  • 请求方法是put、delete
  • Content-Type字段的类型是application/json

2、jsonp【利用script标签跨域特性,动态创建script标签设置src属性为跨域的url,服务端返回响应数据,通过回调函数返回给客户端】

- 前端代码:[前端动态创建一个`<script>`标签,并将它的`src`属性设置为需要访问的 **API 地址**,同时在 URL 中**携带**一个`callback`参数,参数值为一个客户端定义的回调函数名称,例如`handleResponse`]
<script>
    function handleResponse(response) {
      console.log(response); // 处理响应数据
    }

    var script = document.createElement('script');
    script.src = 'https://example.com/api?callback=handleResponse';
    document.head.appendChild(script);
			
</script>

- 后端:[根据前端传入的`callback`参数,生成一个包含 JSON 数据的响应,并将回调函数名称和 JSON 数据作为参数包裹在一个函数调用中返回给前端。]
//例如,如果客户端传入的回调函数名称为`handleResponse`,那么后端返回内容则为
handleResponse({"name":"John","age":30})

3、nginx反向代理

4、postMessage跨域

5、设置代理服务器【在同源策略限制下,可以通过在同域名下的服务器上设置一个代理服务器,将客户端请求转发到目标服务器,再将相应的结果返回给客户端。客户端只需要与代理服务器通信,而不是直接与目标服务器通信,间接实现了跨域请求。】

// App.vue
getName(){
  axios.get('http://localhost:8080/name').then(res=>{})
}
// vue.config.js
const {defineConfig} = require('@vue/cli-service')
module.exports = defineConfig({
  devServer:{
    proxy:''
  }
})

两个域名之间的跨域通信(Hash跨域)

背景

假设我们有两个域名为 a.com 和 b.com 的网站,它们需要进行跨域通信,a.com 的页面需要向 b.com 发送一个消息,让 b.com 的页面展示该消息。

解决方案

在 a.com 的页面中,使用JavaScript代码改变 b.com 页面的URL,将一个特定的hash值传递给 b.com 页面

var message = 'Hello, b.com!';
var url = 'http://b.com/#' + encodeURIComponent(message);
window.location.href = url;

在 b.com 的页面中,使用JavaScript代码监听URL的hash值变化,如果发现hash值发生了改变,就获取传递过来的消息,并展示出来。

window.onhashchange = function() {
  var message = decodeURIComponent(location.hash.substr(1));
  alert(message);
}

浏览器存储数据

Cookie

Cookie主要被用于用户身份的验证,以及用户数据的持久性,主要是为了使无状态的HTTP在某些特殊场景变的有状态,主要体现在我们发送网络请求时,Cookie会被请求头携带,并可以被服务端进行接收,服务端就可以通过Cookie中存储的一些信息进行验证。

  • Cookie的存储大小只有4kb,这是每个HTTP请求都会携带Cookie,所以当我们的存储量过大时会使HTTP请求变慢;

Cookie的一些特性

  • Cookie存储在客户端,但是服务端和客户端都可以对其进行读取设置删除操作;
  • Cookie分为会话Cookie持久性Cookie,前者是没有设置过期时间,只会在当前会话生命周期内存在,也就是说关掉当前页面,cookie就没了,后者则是设置了过期时间,只有超过过期时间使时,才会清除;
  • Cookie是以文本文件的格式进行存储的,查看读取十分方便,所以说最好不要重要信息,否则可能会被窃取;

跨域请求中如何携带cookie?

  •   在前端请求的时候设置request对象的属性withCredentials为true;
    • XMLHttpRequest.withCredentials属性是一个布尔值,表示跨域请求时,用户信息是否会包含在请求中,默认为false。  
<button id="button">同源请求</button>
<button id="cross-button">跨域请求</button>
const button = document.querySelector("#button");
const crossButton = document.querySelector("#cross-button");
button.onclick = function () {
 axios.get("http://localhost:8000/user", {}).then((res) => {})
}
crossButton.onclick = function () {
  axios({
    withCredentials:true,
    method:"get",
    url:'http://localhost:8003/anotherService'
  }).then((res)=>{})
}
  •   服务端在responseheader中配置"Access-Control-Allow-Origin", "http://xxx:${port}";
  •   服务端在responseheader中配置"Access-Control-Allow-Credentials", "true"

Storage

indexedDB

浏览器安全性

XSS攻击

XSS攻击就是跨站脚本攻击,指那些通过在HTML文档中嵌入js脚本的方式,从而获取到用户的私密信息的操作,它主要有三种,分别是存储型反射型文档型

  • 存储型:一般指一些输入框没有做js脚本的校验,导致黑客输入了一些恶意脚本,然后上传至服务器,然后客户端拿到这些数据又进行了执行;
  • 反射型:一般指将恶意脚本作为网络请求的参数发送给服务器,服务器解析之后拼接到HTML文档中发送给客户端,客户端进行执行了这些恶意脚本;
  • DOM-based型:比如一些由用户手动输入然后生成DOM的网站,攻击者将恶意脚本注入到页面中,用户输入内容时,恶意脚本篡改内容,最终执行了恶意脚本,达到了攻击的效果。

如何防止XSS攻击

  • 我们可以通过严格校验用户输入内容过滤一些可能发生风险的输入内容,对一些有特殊含义的字符进行转义
  • 利用HttpOnly,不允许通过浏览器访问cooike,以阻止XSS攻击窃取cookie中的敏感信息;
  • 使用CSP(浏览器安全策略):只允许当前页面加载指定的外部资源,可以通过设置http header中的Content-Security-Policy或者meta标签中的http-equiv属性

CSRF

CSRF就是跨站请求伪造,黑客诱导用户点击链接进入第三方站点,然后通过用户的cookie信息发起而已请求;

如何防止CSRF攻击

  • 设置samesite:通过设置cookie的samesite属性阻止向第三方站点携带cookie信息;
  • 服务端验证额外信息:比如可以给客户端token,然后每次发起请求时让客户端携带token
  • 阻止第三方页面发起请求:可以让服务端阻止第三方网站请求接口;

点击劫持

点击劫持是一种视觉欺骗手段,攻击者将被攻击者的网站通过iframe嵌入到自己的网页中,并且将iframe设置透明,然后放出一个按钮诱导用户点击

如何预防点击劫持

X-FRAME-OPTIONS 是一个 HTTP 响应头,在现代浏览器有一个很好的支持。这个 HTTP 响应头 就是为了防御用iframe 嵌套的点击劫持攻击。

该响应头有三个值可选,分别是

  • DENY,表示页面不允许通过 iframe 的方式展示
  • SAMEORIGIN,表示页面可以在相同域名下通过 iframe 的方式展示
  • ALLOW-FROM,表示页面可以在指定来源的 iframe 中展示

SQL注入

SQL注入就是利用前端输入框校验漏洞以及后端SQL语句漏洞达到攻击目的,比如攻击者可以在输入框输入SQL命令,然后发送给服务端,服务端将SQL命令作为前端参数进行解析执行,可能会执行一些非自己意愿的SQL语句。

如何预防SQL注入

  • 前端严格对输入框内容进行校验,将一些特殊含义的字符进行过滤

  • 服务端对前端参数也要严格进行校验,防止一些非法参数的混入;