浏览器网络面试题(自用,持续更新...)

607 阅读19分钟

GET和POST的区别

  • 应用场景:GET大多数时候是请求数据,POST大多数用于提交数据
  • 缓存:浏览器一般会对GET请求做缓存,对POST不会
  • 传参:GET是查询字符串传参,POST是请求体传参
  • 安全性:GET传参是拼接url上,相对于POST来说不安全
  • 传参长度:浏览器由于对 url 长度的限制,所以会影响 GET 请求发送数据时的长度

POST和PUT的区别

POST提交数据添加种类,PUT提交数据修改数据

POST为什么请求两次

第一次有两个目的:

  • 询问服务器是否支持修改的请求头,如果支持,第二次再发送真正的请求
  • 判断是否跨域

第二次时,才发送真正的POST请求

常见的HTTP请求头和响应头

请求头

  • Accept:浏览器能够处理的内容类型
  • Accept-Charset:浏览器能够显示的字符集
  • Accept-Encoding:浏览器能够处理的压缩编码
  • Accept-Language:浏览器当前设置的语言
  • Connection:浏览器与服务器之间连接的类型
  • Cookie:当前页面设置的任何Cookie
  • Host:发出请求的页面所在的域
  • Referer:发出请求的页面的URL
  • User-Agent:浏览器的用户代理字符串

响应头

  • Date:表示消息发送的时间,时间的描述格式由rfc822定义
  • server:服务器名称
  • Connection:浏览器与服务器之间连接的类型
  • Cache-Control:控制HTTP缓存
  • content-type:表示后面的文档属于什么MIME类型

常见的 Content-Type 属性值有以下四种:

(1)application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码。

(2)multipart/form-data:该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。

(3)application/json:服务器消息主体是序列化后的 JSON 字符串。

(4)text/xml:该种方式主要用来提交 XML 格式的数据。

状态码304是什么情况

304代表浏览器使用的缓存资源

当浏览器请求某一资源时,如果请求的资源和缓存的资源一致,则直接使用缓存的资源,减少网络请求来达到快速响应的目的。一般页面更新周期长或者不更新时,可以考虑使用缓存

HTTP 1.0 和 HTTP 1.1 的区别

  • 连接方面:1.0是非持久连接,1.1是长连接(多个http请求共用一个tcp连接,减少每次建立连接时的时延)
  • 缓存方面:1.0主要是通过 Expires做缓存,1.1通过 If-Match、If-None-Match、If-Unmodified-Since Last-modified做缓存(强缓存和协商缓存)
  • 资源请求方面:1.0存在资源浪费现象,比如浏览器需要的只是对象的某一部分,但是返回的却是整个对象,并且不支持断点续传。1.1在请求头加入了range,允许请求资源的某一部分,状态码是206
  • 请求方法方面:1.1相对于1.0多了 PUT HEAD OPTIONS 等方法

HTTP 1.1 和 HTTP 2.0 的区别

  • 2.0 相对于 1.1 实现了 多路复用。共用一个 TCP 连接,只不过这期间客户端和服务端都可以同时发送多个请求或响应,且不用按照顺序发送,解决了队头阻塞问题
  • 2.0 相对于 1.1 使用了 数据流。一个 TCP 连接里的数据流可能属于不同的请求。因此需要给每一个数据做标记指出它属于哪个请求。
  • 2.0 相对于 1.1 进行了 头部压缩。1.1 不带状态,每次请求都要带上所有的信息。因此很多字段都是重复的,比如一模一样的 cookie 每次都要携带,就会造成资源浪费。2.0 头信息使用 gzip 或者 compress 进行压缩后再发送。再者是客户端和服务端都会维护同一个头信息表,所有字段都会记录在这个表中,因此只需要发索引就行,提高了速度。

什么是队头阻塞

HTTP报文规定一发一收,所以造成了先进先出的一个队列。没有优先级之分,只跟入队的顺序有关。因此如果先入队的请求太费时间就会导致后入队的请求跟着一起等,就会造成时间成本。造成了队头阻塞的现象

队头阻塞的解决方案

  • 并发连接:一个域下分配多个长连接。相对于增加了队列,不至于所有任务在一个队列里面
  • 域名分片:将域名分成多个二级域名,都指向同一个服务器。这样的话长连接的数量增多。

HTTP 和 HTTPS 的区别

  • HTTPS 使用数字证书,费用较高; HTTP不用
  • HTTPS 使用 SSL 加密传输,安全性较高; HTTP使用超文本传输,且是明文传输,安全性较低
  • HTTPS 端口 443; HTTP 端口 80

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么

  • 解析 URL:解析 URL,判断 URL 是否合法
  • 判断缓存:浏览器判断请求的资源是否在缓存中,如果在,则直接使用缓存资源,否则向服务器发请求
  • DNS解析获取 URL 对应的 IP 地址。本地域名 ---》根域名 ---》顶级域名 ---》 权威域名
  • TCP 三次握手:建立连接
  • 发送 HTTP 请求
  • 页面渲染: 根据 HTML 文件构建 DOM 树,根据 CSS 文件构建 CSS 树。当 DOM 树和 CSS树构建完成后,结合成 渲染树。根据 渲染树布局绘制到页面上
  • TCP四次挥手:断开连接

TCP 三次握手过程

  • 第一次:客户端向服务端发送建立连接的请求,服务端收到请求
  • 第二次:服务端向客户端发送响应,同意建立连接
  • 第三次:客户端收到服务端发来的同意信息,告诉服务端收到了同意

TCP 为什么要三次握手

如果是两次握手,在第二次服务器同意连接时,就会建立新的TCP连接,就会导致 客户端不发送请求而 TCP 连接一直存在的情况,会浪费资源

TCP 四次挥手过程

  • 第一次:客户端向服务端发送断开连接的请求
  • 第二次:服务端收到断开连接的请求后,断开 客户端 --》 服务端 的连接。此时客户端不能向服务端发数据,但是服务端可以向客户端发数据
  • 第三次:服务端向客户端发送断开连接的请求
  • 第四次:客户端收到断开连接的请求后,断开 服务端 --》客户端 的连接。会持续 2MSL 的时间,这个时间内如果没有新的请求,就断开了

强缓存

概念:如果存在对应的缓存资源,直接读取该缓存资源,不与服务器交互

原理

Expires:

拿本地时间和 expires 设置的时间做对比。如果在 expires 设置的时间范围内,则读取缓存资源,否则请求服务器获得最新的资源

如果本地时间(电脑的时间)不准确,则判断时就会不准确

Cache-Control:

响应头添加 cache-contrl 的字段,设置资源的缓存时间。比如 cache-contrl: max-age=3600 表示从资源返回后的 3600 秒内,如果资源被请求,则读取缓存资源

cache-contrl的值: - max-age:浏览器资源缓存的时长。 - s-maxage:代理服务器缓存资源的时长。 - no-cache:不走强缓存,走协商缓存。 - no-store:禁止任何缓存策略。 - public:资源即可以被浏览器缓存也可以被代理服务器缓存。 - private:资源只能被浏览器缓存。

协商缓存

last-modified ➕ if-modified-since

流程:

  • 第一次请求时,此时没有 if-modified-since 字段。此时响应头设置 last-modified 字段,然后返回资源
  • 第二次请求时,请求头会带上if-modified-since字段,值就是上一次返回的 last-modified的值,服务器会对比资源的修改时间和 if-modified-since 的时间是否一致。
  • 如果不一致,响应头重新设置 last-modified 字段。并返回资源
  • 如果一致,则返回 304,读取缓存资源。

etag ➕ if-none-match

流程:

  • 第一次请求时,此时没有 if-none-match 字段。服务器读取资源的 hash,此时响应头设置 etag 字段,然后返回资源 第二次请求时,请求头会带上if-none-match字段,值就是上一次返回的 etag的值,服务器会对比资源的 hash 和 if-none-match 的hash 是否一致。
  • 如果不一致,响应头重新设置 etag 字段。并返回资源
  • 如果一致,则返回 304,读取缓存资源。

两种协商缓存,推荐使用 etag ➕ if-none-match。因为是通过hash判断的,每一个文件的hash是唯一的,只要改变了内容,hash就会改变。

对称加密

通信的双方都使用同⼀个秘钥进行加密, 解密。  

⽐如,两个人事先约定的暗号,就属于对称加密。

优点:量小、速度快、效率高

缺点:安全性较低。有一方密钥泄露,加密信息相对于就泄露了

非对称加密

通信的双方都使用不同的秘钥进行加密, 解密。  也就是私钥 + 公钥

特点:公钥可以解密私钥加密的内容;私钥可以解密公钥加密的内容

优点:安全性更好

缺点:速度慢、效率低

场景:HTTPS CA证书

HTTP状态码代表什么意思

类别原因描述
1xxInformational(信息性状态码)接受的请求正在处理
2xxSuccess(成功状态码)请求正常处理完毕
3xxRedirection(重定向状态码)需要进行附加操作一完成请求
4xxClient Error (客户端错误状态码)服务器无法处理请求
5xxServer Error(服务器错误状态码)服务器处理请求出错

token

token是一种身份认证的令牌,一般由 uid+time+sign(签名)+[固定参数] 组成。

token在客户端一般存放于localStorage,cookie,或sessionStorage中。在服务器一般存于数据库中

token 的流程:

  • 用户登录,成功后服务器返回Token给客户端。
  • 客户端收到数据后将 token 保存在客户端
  • 客户端再次访问服务器,将token 放入请求头中或者请求参数中
  • 服务器端根据 token 进行校验。校验成功则返回请求数据,校验失败则返回错误码

token 是怎么加密的

  • 通过一个随机数和加密算法,生成对应的 token,返回给前端。
  • 前端每次请求时带上 token
  • 后端用相同的算法解密

为什么会劫持cookie,不会劫持token

因为 cookie 登录后,后端会记录 sessionid 并返回,客户端每次请求都带上这个 sessionid,服务端通过 sessionid 去验证身份之类的。所以如果别人拿了你的 cookie 就可以取代你

而 token 是每次手动添加到 请求头或者请求参数里的。浏览器不会自动携带 token,所以不会劫持 token。

token 无感刷新

在响应拦截器中拦截,判断Token 返回过期后,调用刷新 token 接口。

Cookie、LocalStorage、SessionStorage区别

cookie:由服务器设置,在客户端存储的一种文本信息。最大 4kb。每次请求时会把 cookie 带给服务端。并且 cookie 只能被同源页面访问

LocalStorage:浏览器本地存储的方法。如果不手动删除它,否则它不会失效,并且 localStorage 也只能被同源页面所访问共享。

SessionStorage: 浏览器本地存储的方法。它只能在当前窗口生效。如果当前窗口关闭后就失效了。并且 sessionStorage 只能被同一个窗口的同源页面所访问共享。

什么是同源策略

protocol(协议)、domain(域名)、port(端口)三者必须一致

跨域

不满足同源策略的情况就是跨域

如果跨域:

  • 不能跨域请求
  • 不能跨域操作 DOM
  • 不能跨域读取 cookie localStorage 等

解决跨域

本人的实际项目中,跨域都是后端解决的。

  • CORS:只要服务器实现了 CORS,就解决了跨域
  • JSONP:利用 script 标签没有跨域限制,通过 script 标签的 src 属性发送带有 callback 的 GET 请求,服务端返回数据拼接到 callback 给浏览器。浏览器解析拿到 callback 的数据
  • PostMessage(data, origin)
    • window上的一个属性
    • 页面与嵌套的iframe消息传递、多窗口之间消息传递
    • data 参数:任意基本类型或可复制的对象。部分浏览器只支持字符串,所以建议通过 JSON.stringify()序列化。
    • origin 参数:要传递给哪个地址。由协议+主机+端口号组成,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

浏览器是如何进行界面渲染的?

  • 获取 HTML ⽂件并进⾏解析,生成一棵 DOM 树(DOM Tree)

  • 解析 CSS,⽣成样式 CSS规则树(sStyle Rules)

  • 根据 DOM 树和 CSS规则树,生成一棵渲染树(Render Tree)

  • 进行布局(Layout)(重排),即为每个节点分配⼀个在屏幕上应显示的确切坐标位置

  • 进⾏绘制(Paint)(重绘),遍历渲染树节点,调⽤ GPU(图形处理器) 将元素呈现出来

JS和CSS的阻塞

  • css不会阻塞 DOM的解析,但是会阻塞 DOM的渲染,严谨一点说,css会阻塞渲染树的生成,进而会阻塞DOM的渲染

  • JS会阻塞DOM解析,但是可以使用defer或者async解决

  • css会阻塞js的执行

  • 如果js脚本中是获取dom元素的css样式属性,为了获取到最新的正确的样式,需要所有的css加载完成,否则获取的样式可能是错误的或者不是最新的。要等到js脚本前面的css加载完成,js才能再执行。所以一般cdn引入第三方库的script一般放在link之前

  • 浏览器遇到<script>标签且没有deferasync属性时会触发页面渲染。 浏览器解析DOM时,虽然是一行一行地向下执行,但是它会预先加载具有引用标记的外部资源(例如带有src标记的script标签)。 在解析到此标签的时候,则无需再去加载,直接运行,以此提高运行效率。浏览器无法预先知道脚本的具体内容,因此碰到script标签时,只好先渲染一次页面,确保script脚本内能获取到dom最新的样式。如果在决定渲染页面时,还有尚未加载完成的css文件,只能等待其加载完成再去渲染页面

前端如何实现即时通信?

HTTP 只能 客户端向服务端发请求,服务端做响应。

而如果服务器向主动通知客户端,就可以使用 websocket 实现即时通信

websocket只需要建立一次连接,就可以一直保持连接状态

重排(Reflow)和重绘/回流(Repaint)

(重排必定会发生重绘,重绘不一定会引发回流。)

  • 重排 —— 布局或者几何属性需要改变
    • 添加或删除可见的DOM元素
    • 元素的位置发生变化
    • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
    • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
    • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
    • 浏览器的优化机制
    • 读取属性引起回流: 由于每次回流都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化回流过程。浏览器会在过了一段时间或者操作达到了一个阈值,才清空队列。但是!当你获取布局信息的操作的时候,为了保证准确,会强制队列刷新,比如当你访问以下属性或者使用以下方法:
clientWidth、clientHeight、clientTop、clientLeft、offsetWidth、offsetHeight、offsetTop、
offsetLeft、scrollWidth、scrollHeight、scrollTop、scrollLeft
scrollIntoView()、scrollIntoViewIfNeeded()、getComputedStyle()、getBoundingClientRect()
scrollTo()
  • 重绘 —— 当节点需要更改外观而不会影响布局的,比如改变 color

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility 等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

浏览器针对页面的回流与重绘,进行了自身的优化——渲染队列

浏览器会将所有的重排、重绘的操作放在一个队列中,当队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的重排、重绘变成一次重排重绘。

将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,原本应该是触发多次重排,变成了只触发一次重排。

  • 具体措施

    • 批量操作 DOM

      • DocumentFragment一次性插入多个节点(避免逐次插入触发多次回流)。
      • 批量修改样式时,先通过className切换类名(而非逐行修改style属性)。
    • 避免频繁触发回流

      • 不频繁获取布局属性(如offsetWidthscrollTopgetBoundingClientRect),此类操作会强制浏览器同步计算布局,可缓存结果后复用。
      • 动态修改元素时,先设置display: none(触发 1 次回流),修改完成后再恢复display(再触发 1 次回流),避免中间多次回流。
    • 脱离文档流减少关联影响

      • 动画元素、浮动元素用position: absolute/fixedtransform(触发 “合成层”,避免影响其他元素布局)。
      • 复杂组件(如弹窗、下拉菜单)单独创建图层(通过will-change: transform提示浏览器提前优化,避免突然性能波动)。
    • 简化 DOM 结构

      • 减少 DOM 嵌套层级(避免深层级导致布局计算复杂)。
      • 避免使用table布局(table的一个单元格变化会触发整个表格回流)。

优化 CSS 渲染效率

CSS 会阻塞渲染(浏览器需等待 CSSOM 构建完成后才开始布局),优化核心是减少 CSS 计算成本和避免阻塞关键渲染。

  • 具体措施

    • 精简 CSS 选择器

      • 避免复杂嵌套选择器(如div:nth-child(2) > .class ~ span),浏览器匹配选择器是 “从右向左”,复杂选择器会增加计算时间。
      • 优先使用类选择器(.class),避免标签 + 类选择器(如div.class,增加匹配成本)。
    • 拆分 CSS 资源

      • 首屏必需的 “关键 CSS” 内联到<style>标签(避免外部 CSS 文件加载延迟导致渲染阻塞)。
      • 非首屏 CSS(如折叠区域、异步组件样式)通过rel="preload"异步加载(加载完成后通过 JS 切换为stylesheet)。
    • 避免触发布局抖动

      • 不混合读写布局属性(如先读offsetWidth再写width,会强制浏览器频繁同步布局),建议 “先批量读,再批量写”。

优化 JavaScript 执行(避免阻塞主线程)

JS 执行与渲染共用主线程,长任务(>50ms)会阻塞渲染,导致页面卡顿。

  • 具体措施

    • 拆分长任务

      • setTimeoutrequestIdleCallback将长任务拆分为微任务(如大数据处理、复杂计算),避免独占主线程。
      • 复杂逻辑(如数据格式化、图表渲染)放入Web Worker(独立线程,不阻塞渲染)。
    • 优化事件监听

      • 高频事件(scrollresizemousemove)用 “节流”(限制触发频率,如每 100ms 一次)或 “防抖”(延迟触发,避免连续触发)。
      • 避免在loadDOMContentLoaded等关键时机执行重计算,优先处理首屏渲染。

动画与滚动优化(提升视觉流畅度)

动画和滚动是渲染性能的重灾区,需优先使用 “合成层” 渲染(浏览器通过 GPU 加速,避免布局 / 绘制)。

  • 具体措施

    • 用 CSS3 属性实现动画

      • 优先使用transform(位移、缩放)和opacity(透明度),这两个属性仅触发 “合成” 阶段(GPU 加速,无回流 / 重绘)。
      • 避免用top/left/width等属性做动画(会触发频繁回流)。
    • 合理创建合成层

      • 对动画元素添加will-change: transform(提示浏览器提前准备合成层),但避免滥用(过多合成层会占用大量 GPU 内存)。
      • 滚动列表用position: fixed固定容器,避免滚动时整个页面布局重计算。

 浏览器渲染过程中遇到 JS 文件如何处理?

HTML 解析器若遇到了 JavaScript,那么它会暂停文档的解析,将控制权移交给 JavaScript 引擎,等 JavaScript 引擎运行完毕,浏览器再从中断的地方恢复继续解析文档。

也就是说,如果想要首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因

当然也可以给 script 标签添加 defer 或者 async 属性异步解析。

script标签的 defer 和 async 有什么区别

  • defer 会按照顺序加载;async 不会
  • defer 要等到文档加载完成后执行;async 加载完成后立即执行

image.png