浏览器相关
(1) 浏览器缓存
-
HTTP 缓存: 当客户端向服务器请求资源时,会先查看浏览器缓存,如果浏览器有请求资源的副本,就可以直接从浏览器缓存中提取,而不用去原服务器中提取资源。HTTP 缓存分为 强缓存 与 协商缓存。
-
强缓存: 如果缓存中有请求的数据,就直接去缓存中提取数据。如果缓存中没有要请求的数据,这是客户端会从服务端获取数据,并且服务器会将数据和缓存规则一起返回,将缓存规则信息包含在响应头中。与强缓存有关的响应头字段:
- Expires :告知客户端资源失效的日期
- Cache-Control:属性很多,用来控制缓存机制(优先级高)
- private:对指定的客户端提供缓存
- public:任何客户端与代理服务器都可以缓存
- max-age: 缓存资源在t秒之后失效
- no-cache: 使用协商缓存
- no-store:任何资源都不缓存
-
协商缓存: 当第一次请求时服务端返回的响应头中没有 Cache-Control 和 Expires 或者 Cache-Control 和 Expires 过期或者 Cache-Control 的属性为 no-cache 时,第二次请求就会进行协商缓存。进行协商缓存时,客户端会从缓存中获取一个标识,得到标识后发请求去服务端验证是否失效,没有失效返回304,失效后服务器返回最新资源与缓存规则信息,之后将资源与规则信息存入缓存中。与协商缓存有关的响应头字段:
- Last-Modified: 告知客户端资源最后修改的时间(If-Modified-Since)
- Etag: 告知客户端当前资源在服务器生成的唯一标识。(If-None-Match)(优先级高)
-
协商缓存的具体过程: 当浏览器第一次向服务器发送请求时,会在响应头中返回协商缓存的头部字段:ETag 和 Last-Modified,ETag 返回的是一个 hash 值,Last-Modified 返回的是资源修改的最后时间。在浏览器第二次发送请求时,会在请求头中带上与 ETag 对应的 If-None-Match,其值就是响应头中返回的 ETag 值,Last-Modified 对应的 If-Modified-Since。服务器在接受参数后会做比较,如果资源没有修改,返回304,浏览器可以直接在缓存中取数据,否则,服务器会直接返回数据和缓存规则。
(2) 跨域
浏览器的同源策略: 同域名 、同协议、同端口,当三者不一相同时,就是跨域了。如果不没有同源策略,浏览器很容易受到 XSS、CSRF 攻击。
跨域的解决方法:(常用的)
- CORS:原理通过自定义HTTP头部让浏览器与服务器进行通信
- JSONP:原理通过 script 标签不受同源策略的限制
- Nginx:代理
- WebSocket: HTML5的新协议,实现浏览器与服务器之间的全双工通信,允许跨域
(3) 浏览器的渲染过程
- 解析 HTML 生成 DOM 树,解析 CSS 生成 CSSOM 树
- 构建 Render 树: 通过 DOM 树与 CSSOM 树生成 Render树
- 布局: 根据 render 树进行布局,确定各节点的在屏幕上的位置,生成布局树
- 绘制: 遍历布局树,确定各元素的绘制顺序,得到绘制记录
- 合成: 遍历布局树,生成层树。合成线程将图层划分为图块,并将每个图块发送到栅格线程,栅格线程栅格化每个图块转为位图,并存到 GPU显存中。所有图块变成位图之后,合成线程会收集每个位图信息创建合成帧,合成帧通过 ipc 协议传递给浏览器主进程,浏览器主进程收到消息后,会将页面内容绘制到内存中,最后再将内存显示到页面上。
补充:浏览器解析css是从右向左,这样极大的缩小了查找范围从而提高了性能。
比如:
#molly div.haha span{color:#f00}
(4) 回流与重绘
-
回流: 浏览器发现某个元素的变化影响到了布局就会进行回流。(比如添加或删除元素、元素的位置/尺寸发生变化、浏览器的窗口尺寸变化等等)
-
重绘: 当元素的背景颜色、字体颜色等非几何信息发生变化后,会进行重绘。
-
回流必定会引起重绘, 回流比重绘更消耗性能。
优化:
-
css 方面:
- 使用 transfrom 代替 top、left、margin-top等位移属性。
- 避免使用 table 布局
- 使用 visibility 代替 display:none, 前者只会引起重绘,后者引起回流。
- 使用 css3 硬件加速
- 使用 flex 布局代替老的布局模型
-
js 方面:
- 避免频繁操作样式
- 避免频繁操作DOM
- 少使用影响布局的属性:offset家族(offsetTop、offsetLeft、offsetWidth、offsetHeight)、 scroll家族、client 家族、geComputedStyle() 等
- 动画使用requestAnimationFrame:保证 callback 函数在每帧动画开始的时候执行
(5) 浏览器的进程与线程
进程与线程的定义:
-
进程是CPU资源分配的基本单位(平时开启的应用,比如 QQ、微信等只要运行的应用程序就会有一个进程)进程之间是相互独立的。
-
线程是进程中的一个实体,是一个基本的 CPU 执行单元,线程不拥有资源。
浏览器中的多进程:
每个进程都被分配了资源(CPU、内存),浏览器中的主要进程有:
- 浏览器主进程:只有一个,主要负责浏览器页面的管理、子进程的管理、书签、前进后退、资源下载管理等
- 渲染进程:每一个 tab 页面就是一个进程
- GPU 进程: 最多一个,用于 3d 绘制
- 第三方插件进程:每种类型的插件对应一个进程
- 网络进程: 负责页面的网络资源加载
多进程的优势:
- 防止一个页面崩溃影响整个浏览器
- 充分利用 CPU 多核的优势
- 安全性和沙箱: 沙箱模式基本单位为一个进程,一个进程对应一个沙箱,限制进程的环境。(沙箱对进程可访问的内存地址做出限制)
- 其他第三方插件崩溃不会影响整个浏览器
浏览器中的多线程:
以渲染进程为例子,一个渲染进程需要多个线程来协助工作:
- GUI 渲染线程: 负责页面的渲染,解析 HTML、CSS 、布局绘制等
- JS 引擎线程:解析、执行 js 代码
- 事件触发线程:维护一个任务队列,所有异步的回调函数都会加入到这个任务队列中,等待 JS 引擎线程的执行。
- 定时器线程:定时器所在的线程
- 异步 HTTP 请求线程: 负责异步请求的线程
注意: GUI 渲染线程与 JS 引擎线程互斥
(6) cookie、session、token的区别
网络相关
(1) TCP/IP 四层模型 、OSI七层模型、每一层的有哪些常见的协议
(2) TCP 与 UDP 的区别
TCP(传输控制协议) 与 UDP(用户数据报协议) 都是传输层的协议。
- TCP 是面向连接的可靠传输协议 , UDP 是无连接的不可靠传输协议
- TCP 是点对点的,UDP 支持一对一、一对多、多对多
- TCP 有拥塞控制与流量控制的机制,而UDP没有
- TCP 首部最少是20个字节,UDP首部是8个字节
(3) TCP 的 三次握手与四次挥手(为什么是三次? 为什么是四次?)
-
三次握手
三次握手的目的是: 确定双方接受能力与发送能力是否正常。
为什么是三次而不是两次或者四次:- 如果是两次,那服务端不能确定客户端的接受能力是否正常
- 四次以上都可以,但是三次足以确定双方的发送与接收能力,不必再需要其他的连接
-
四次挥手
由于TCP连接具有半关闭状态,即建立TCP连接的某一端结束发送之后还具有接收数据的能力。
挥手为什么是四次?关闭连接时,服务器收到 FIN 报文时,可能数据还没发完,就不会立即关闭连接,只能先回复一个ACK 报文段,告诉客户端“你发送的 FIN 报文段我收到了”。只有等服务器的数据都发送完毕了,才能发送 FIN报文段释放连接。所以要四次挥手。
(4) TCP 可靠传输
TCP 的可靠传输是基于连续重传 ARQ 协议实现的。可靠传输的发展历程:
- 停止等待协议:每发送完一个分组就停止发送,等待对方的确认。在收到确认再发送下一个分组。
- 自动重传请求 ARQ 协议:在停止等待协议中超时重传的自动重传的方式为自动重传请求 ARQ 协议。即只要超过一段时间没有收到确认,就重传前面发送过的分组。(信道利用率低)
- 连续ARQ协议:发送方维持一个发送窗口,凡是位于发送窗口内的分组连续发送出去,而不需要等待对方的确认。接收方采用累计确认,对按序到达的最后一个分组 发送确认,表明到这个分组为止的所有分组都已经正确收到了。(优点:信道利用率高,缺点:不能向发送方反映接收方已经正确收到的所有分组的信息)
(5) TCP 滑动窗口
通信双方同时拥有发送窗口 与 接受窗口 这两个窗口。
发送方通过接受方发送的确认报文中的窗口字段来确定自己发送窗口的大小。
(6) TCP 的 流量控制与拥塞控制
- 流量控制:为了控制发送方的发送速率,保证接收方来得及接收。使用滑动窗口来实现流量控制。
- 拥塞控制:为了降低整个网络的拥塞程度。
- 拥塞控制的算法:慢开始、拥塞避免、快重传、快恢复。
- 慢开始:设置一个阈值 ssthresh , cwnd 初始值为1,成指数增长。
- 拥塞避免:当 cwnd >= ssthresh 时,cwnd 开始线性增长。当出现超时,ssthresh = cwnd / 2, cwnd = 1,重新执行慢开始。
- 快速重传:当发送方收到3个ACK确认报文时,就知道下一个报文段丢失,立即重传下一个报文段。
- 快速恢复:上述情况下,是丢失个别报文,而不是网络拥塞。此时执行快恢复,ssthresh = cwnd / 2 ,cwnd = ssthresh,之后直接进入拥塞避免。
(7)说一下 HTTP 协议
HTTP 是超文本传输协议,是客户端与服务端通信之间通信的规则。它是基于 TCP/IP 四层协议中的应用层协议。
HTTP的特点:
- 无状态: 对于之前的交互没有记录。
- 两种连接模式:HTTP1.0 以前是非持续连接,每次TCP只能发送一次请求;HTTP 1.1 以后是持续连接,TCP连接默认不关闭,可以被多个请求复用,默认开启 Connection: keep-alive。
HTTP 请求方法:
- GET、POST 、HEAD、 OPTIONS、PUT、DELETE、CONNECT和TRACE
HTTP请求报文
请求报文包括:
- 请求行: 请求方法、URL、协议及版本号
- 请求头部:常见请求头部字段: Host、Content-Type、User-Agent、Referer、Connection-Control、Cookie、Origin (cors请求)等等
- 空行: 划分实体
- 请求数据(实体)
HTTP响应报文
响应报文包括
- 状态行:协议及版本、状态码、状态码描述
- 响应头部:常见的响应头字段:Access-Control-Allow-Origin、Server、Content-Type、Date等等
- 空行:划分实体
- 响应数据(实体)
HTTP 状态码
-
1XX(信息)— 表示请求以接受,继续处理
-
2XX(成功) — 表示请求已经被成功接受
-
3XX(重定向) — 表示要完成请求必须进行附加操作
-
4XX(客户端错误)— 请求有语法错误或请求无法实现
-
5XX (服务端错误) — 服务器处理某个正确的请求时发生错误
常见的状态码:
- 200: 请求成功
- 301: 永久重定向
- 302:临时重定向
- 304: 请求资源未修改,服务器不放回任何资源
- 400:请求存在语法错误
- 401:未授权,请求需要通过HTTP认证
- 403: 请求被拒绝
- 404:资源不存在
- 500:服务器发生不可预期的错误
- 503:服务器暂时不能处理当前的客户端请求,一段时间恢复
(8) GET 与 POST的区别
从表现上看:
- GET请求在浏览器回退时不会再次请求,POST会再次提交请求。
- GET请求会被浏览器缓存,POST不会(需要手动设置)
- GET 请求在URL中传送的参数是有限的,而POST没有限制
- GET请求的参数通过URL传递,POST 放在 Request body中
- GET 相比与 POST 安全性差一些
从本质上看:
- GET 与 POST 都是 HTTP 协议的请求方式,本质上还是基于TCP连接,在传输上没有区别。
- GET 方法的参数在URL,POST 参数在请求实体里,但由于本质一样,所以也可以互换参数的位置,只不过前者是一种规范。
- GET 请求的参数在URL上受限制,并不是HTTP协议的限制,大多数对 URL 的限制都是浏览器与服务器。因为过大的数据会给浏览器与服务器造成很大的负担,所以通常浏览器能限制 URL 长度为 2K,而服务器最多处理 64K 的 URL。
- 从传参角度讲:GET 方法将参数暴露在 URL中比POST方法的确更容易遭受攻击;从传输的角度,两者都不安全,因为 HTTP 在网络上是明文传输,要想安全传输,就要加密,使用 HTTPS 协议。
(9) HTTP1.0 、HTTP1.1 、HTTP 2.0
HTTP 1.0 与 HTTP 1.1 的区别:
- HTTP 1.0 默认短连接,想要强连接必须设置connection:keep-alive;HTTP 1.1 默认长连接。
- HTTP1.1 强制设置 Host 请求首部字段来指定服务器域名。
- HTTP1.1 支持管线化:不用等待响应,就可以发送下一个请求。但是服务器必须按照客户端的请求先后顺序依次回送相应的结果。
- HTTP1.0 是 Expires 来控制缓存; HTTP 1.1 新增 Cache-Control 来控制缓存
- HTTP 1.0 中存在浪费带宽的现象,比如客户端只需要某个对象的一部分,而服务器却将整个对象全部返回;HTTP 1.1 带宽优化,增加 range 请求头部字段,允许客户端只请求服务器某个对象的一部分资源(支持断点续传)。返回 206状态码 表示请求一部分资源成功,否则返回200,返回对象的全部资源。
相比 HTTP 1.0 ,HTTP 1.1 的优点很多,但是还是还是有很多不足:
- 队头阻塞: HTTP 1.1 支持管线化,允许一次发起多个请求,但是服务器会按照请求顺序响应。一旦响应某个请求出现了阻塞,那么后面的请求即使2处理完毕,任然要等待阻塞的请求处理完毕。
- 头部信息冗余:每次请求都会带上一些相同的首部。
HTTP2.0
核心是在应用层与传输层中新增二进制分帧层,采用二进制格式传输数据而不是1.x 的文本格式,这样对计算机更友好。
在 2.0 中消息被分为两个帧:HEASERS 帧和 DATA帧,首部信息封装在 HEASERS 帧,实体信息封装在 DATA帧中,每个帧采用二进制编码。
在 HTTP 2.0 中 提出流的概念,是一个虚拟信道,可承载双向的消息,每个流都有一个唯一的整数标识符。
HTTP 2.0 的特点:
- 多路复用:一个TCP连接上可以有任意多个流,消息分割为多个帧在流里面传输。帧传输过去之后,在进行重组,形成完成的请求和响应。(stream 是乱序的,而同一个Stream里面的帧是按序传输的,二进制帧到达后,对方将 Stream ID 相同的二进制帧组装成完整的请求报文与响应报文)
- 请求优先级:为并发的请求设置优先级,重要的请求会先响应。
- 头部压缩:采用 HPACK 压缩算法来压缩头部。
- 服务器推送:支持服务器主动向客户端推送数据的功能。
(10) HTTP 与 HTTPS 的区别 、HTTPS的握手过程
-
HTTP 是明文传输,在传输的过程中,消息容易被窃取、无法验证通信双方的身份、无法保证数据的完整性。
-
HTTPS 就是弥补 HTTP 的不足,在应用层与传输层加了一层 TLS 协议,来进行通信加密。HTTPS 做到了 加密、数据一致性、身份认证
-
加密
- 对称加密:加密和解密使用同一个密钥。缺点:如果密钥被窃取,任何人都可以解密。(加密算法 AES)
- 非对称加密:一般用公钥加密,私钥解密,私钥只有自己使用。(还是会受到中间人攻击,因为无法验证公钥是否是所请求的服务器的公钥)
-
数据完整性
为保证数据完整性: 使用摘要算法将数据生成摘要,摘要算法不可逆,这样就保证了数据的完成性。 -
身份验证
要想验证 server的身份,需要 CA 机构来为 server 颁发一个数字证书。
server 将公钥、个人信息、其他信息发给CA机构 => CA 机构使用 hash 算法将信息生成摘要 => 使用CA 私钥加密摘要生成数字签名 => CA 机构将server的公钥、个人信息、其他信息与数字签名生成数字证书颁发给server
浏览器拿到数字证书后,使用同样的 hash 算法将server发送的公钥、个人信息、其他信息生成摘要,再使用内置的 CA公钥解密数字签名,得到另一份摘要,比对两份摘要,相同则信任此server的公钥。 -
HTTPS 的加密过程
- 浏览器发加密请求:带上 client_random 随机数,和加密套件列表。
- 服务端响应:返回 server_random 随机数、server_params参数、确认加密套件列表、数字证书
- 客户端验证数字证书:证书通过后,使用服务器的公钥加密 client_params 参数并传递给服务器。接着客户端通过 ECDHE 算法生成 pre_random(基于client_params与server_params),最后将三个随机数通过伪随机函数计算最终的对称密钥
- 服务端生成对称密钥:服务端用私钥解密 client_params,同样使用 ECDHE 算法计算 pre_random,最后通过伪随机函数计算最终的对称密钥
(11) DNS 协议
- DNS 协议提供的是一种域名到 IP 地址的转换服务。DNS 协议运行在 UDP 协议上,端口为 53。
- 主机向本地域名服务器查询一般采用递归查询;本地域名服务器向其他域名服务器的查询是迭代查询。
- 域名解析的详细过程:
浏览器缓存 => 系统的 Host 文件(操作系统缓存) => 路由缓存 => 本地域名服务器 => 根域名服务器 => 顶级域名服务器 => 权限域名服务器 => 本地
域名服务器保存结果到缓存中,同时将结果返回给客户端。
(12) 输入 URL 回车之后发生了什么?
- 域名解析
- 建立TCP 连接
- 浏览器发送HTTP 请求
- 服务器做出 HTTP 响应
- 浏览器解析渲染页面
- 释放TCP连接
每一点可以进行详细的展开。
(13)XSS 攻击及如何防范
XSS 攻击
- XSS 跨站脚本攻击:在浏览器中执行恶意的脚本,从而拿到用户的信息并进行操作
- 存储型: 服务器将用户输入的恶意脚本,未经验证存储在数据库中,然后在客户端执行这些脚本。(留言评论区提交一段脚本代码)
- 反射型: 在 URL 中包含恶意脚本。脚本通过网络请求作为参数,经过服务器,然后再反射到 HTML 文档中,执行解析。
防范
- 不要相信任何用户的输入,不管是前端还是服务端,都要对用户的输入进行转码或者过滤。
- 过滤特殊HTML 标签 < script > 、< iframe>
- “<”、“>”、“&”等这特殊字符不能直接使用,需要转为实体字符。
- 设置 HTTPOnly,这样 js 就无法读取 Cookie 的值。
- 利用 CSP(浏览器中的内容安全策略) : 服务器决定浏览器可以加载哪些资源。
(14)CSRF 攻击及如何防范
CSRF (跨站请求伪造):攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。
防范
- 添加验证码
- 使用 Referer 判断请求的来源
- 使用 Token : 服务器给用户生成一个 token ,加密之后传递给用户;用户在提交请求时,带上这个 token;服务端验证 token 是否正确
- 设置 Cookie 的 Samesite 属性为Strict,这样任何情况在这个Cookie 都不可能作为第三方Cookie。