浏览器及HTTP常考点

实验介绍

作为一个前端开发人员,浏览器对我们的重要性不言而喻。当然浏览器作为网页应用的载体本身就十分的重要,随着 Web 特性的极大丰富和浏览器性能的提升,越来越多的项目可以用 Web 来开发,学习浏览器工作原理可以让我们站在更高维度上来审视项目,可以看到项目的瓶颈。而 HTTP 作为在浏览器中使用最多的通讯协议,其重要性更是不言而喻,比如什么是三次握手?什么是跨域?什么是 TCP 等。学完本章节你将从根源上找到答案并不再惧怕此类问题。

知识点

HTTP 状态码

面试中经常被问到:你知道 HTTP 状态码都有哪些吗?下面我们就来具体学习下这个知识点。

首先状态码分为以下几种类型:

  1. 2XX

2XX 类状态码表示服务器收到并成功处理了客户端的请求,这也是客户端最愿意看到的状态码,常见以 2 开头的状态码有:

  • 200 是最常见的成功状态码,表示一切正常,服务器如客户端所期望的那样返回了处理结果;

  • 204 它的含义与“200 OK”基本相同,但响应头后没有 body 数据;

  • 206 是 HTTP 分块下载或断点续传的基础,在客户端发送“范围请求”、要求获取资源的部分数据时出现,它与 200 一样,也是服务器成功处理了请求,但 body 里的数据不是资源的全部,而是其中的一部分。

  1. 3XX

3XX 类状态码表示客户端请求的资源发生了变动,客户端必须用新的 URI 重新发送请求获取资源,也就是通常所说的“重定向”,包括著名的 301、302 跳转,常见以 3 开头的状态码有:

  • 301 俗称“永久重定向”,含义是此次请求的资源已经不存在了,需要改用新的 URI 再次访问;
  • 302 临时重定向,意思是请求的资源还在,但需要暂时用另一个 URI 来访问;
  • 304 它用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制。它不具有通常的跳转含义,但可以理解成 “重定向到已缓存的文件”。
  1. 4XX

4XX 类状态码表示客户端发送的请求报文有误,服务器无法处理,它就是真正的“错误码”含义了,常见以 4 开头的状态码有:

  • 400 表示请求报文有错误,但具体是数据格式错误、缺少请求头还 是 URI 超长它没有明确说,只是一个笼统的错误;
  • 403 表示服务器禁止访问资源;
  • 404 资源在本服务器上未找到,所以无法提供给客户端。
  1. 5XX

5XX 类状态码表示客户端请求报文正确,但服务器在处理时内部发生了错误,无法返回应有的响应数据,是服务器端的“错误码”,常见以 5 开头的状态码有:

  • 500 服务器内部错误;
  • 501 表示客户端请求的功能还不支持;
  • 502 通常是服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常,访问后端服务器时发生了错误;
  • 503 表示服务器当前很忙,暂时无法响应服务。

关于状态码的知识,没有什么需要理解的东西,更多的是需要我们去记忆。

浏览器跨域

为什么有跨域问题,前端如何解决跨域问题?跨域问题基本上是面试中必考题,下面我们来具体学习什么是跨域问题,以及跨域是如何产生并解决的。

为什么存在跨域问题

首先我们可以试想一下,如果没有跨域的存在会发生什么事,也就是说我们可以任意的在浏览器中请求任何服务器的资源,更有甚者做个恶意的网站通过 iframe 嵌入银行的登录页面,恶意网页上的 javascript 脚本就可以在用户登录银行的时候获取用户名和密码。这样一来网络将不再有安全可言。

所以为了网络的安全性,跨域的存在是非常必要的,而之所以存在跨域问题就是因为浏览器同源策略的限制,下面我们来具体学习下什么是同源策略。

同源策略是指浏览器不能去请求域名、端口、协议任何一个不相同的服务器资源,如下所示:

浏览器服务器是否跨域
http://www.aabb.com:8081http://www.aabb.com:8080跨域(端口不同)
http://www.aabbcc.comhttp://www.aabb.com跨域(域名不同)
http://www.aabbcc.comhttps://www.aabbcc.com跨域(协议不同)
http://www.aabbcc.comhttp://www.aabbcc.com不跨域

我们在平常开发中如果就需要从前端服务去请求后端服务的接口,且这两个服务地址还不一样,那如果解决这个问题呢?

如果你用的是 Vue/React 在开发环境中可以配置反向代理模式去解决跨域问题,拿 vue 为例,如下所示:

​
// vue.config.js
module.exports = {
  devServer: {
    // 配置反向代理
    proxy: {
      "/api": {
        // 以/api开头的请求
        target: "https://xxx.com", // 以/api开头的请求,全部代理到https://xxx.com上
        // ws: true,
        changeOrigin: true,
      },
    },
  },
};

​

反向代理的原理就是把目标服务器的请求代理到自己的服务器中,这样就实现了在自己的服务器中去请求自己的接口资源,当然就不存在跨域问题了。当然在生产环境中我们也可以配置 nginx 的反向代理来解决跨域问题

如果服务的响应报文包含了正确 CORS 响应头,那么前后的通讯就不再存在跨域问题,可以理解为在后台服务中开启了白名单。所以本质上来讲,解决跨域问题还是需要后端处理,如下所示:

Access-Control-Allow-Origin: *

以上设置表示该资源可以被任意外域访问,如果服务端仅允许来自 http://xxx.com 的访问,该首部字段的内容如下:

Access-Control-Allow-Origin: http://xxx.com

除了以上常用的解决跨域问题外,在前端还可以使用 JSONP 方式解决跨域问题。

浏览器的同源策略对 JavaScript 脚本向不同域的服务器请求数据进行了限制,但是没有对 HTML 中的<script>标签进行限制,我们可以基于此规则,动态创建<script>标签进行跨域资源访问。<script>标签中 src 这一属性值设置为:接口地址+处理数据的回调函数名称。相关代码示例如下:

​
var script = document.createElement("script");
script.type = "text/javascript";
// 设置接口地址+数据获取成功后的回调函数(handleData)
script.src = "http://xxx.com/api/list&callback=handleData"; // 通常为后端提供的接口
document.body.appendChild(script);
// 回调执行函数
function handleData(res) {
  data = JSON.stringify(res);
  console.log(data);
}

​

在这里值得注意的是,因为请求数据的接口地址是写在了<script>标签中 src 这一属性值里面,那么数据请求的方式就只能支持 GET 请求,其他请求无法实现。目前常用于解决请求第三方服务,比如解决调用百度地图 API 的跨域问题。

我们来总结下这个问题:存在跨域是为了保证用户的隐私和数据安全,跨域问题是因为浏览器的同源策略,即如果两个 URL 的协议、域名和端口都相同,我们就称这两个 URL 同源否则就不同源(跨域)。跨域本质上是后端解决,当然在开发环境下我们可以配置反向代理来解决跨域,对于那些第三方的接口,可以使用 jsonp 的形式解决跨域。

三次握手

面试中经常被问到,说说什么是三次握手,为什么不叫四次握手?

在工作中前后端用的最多的通讯协议就是 TCP/IP,而我们熟悉的 HTTP/HTTPS 协议就是 TCP/IP 协议的上层应用,三次握手是服务端与客户端建立 TCP 连接的关键。也就是说只有先建立了 TCP 连接,我们才能使用 HTTP/HTTPS 传输数据。

现在我们知道了三次握手的目的就是为了建立 TCP 连接。那为什么要设计成三次握手呢?两次不行吗?下面我们进行深入的学习。

假设是两次握手后建立 TCP 连接,连接过程应该是这样的:当服务器收到对端的连接请求时,就认为连接建立好了,进入 ESTABLISHED 状态。客户端在收到服务器发来的同步确认报文后,就认为连接建立好了,进入 ESTABLISHED,在报文都能正常收到的情况下,两次握手是可以安全建立连接的。

但是存在这样的情况,假设第二次握手的报文丢失了,当前的状态是,服务器认为连接已经建立好了,可是客户端没有收到同步确认报文,认为连接还没有建立好,此时,服务器端的连接其实是无效连接,客户端因为没有收到确认,便会向服务器重传同步报文,同样,在服务器收到客户端的同步报文时,认为连接已经建立好了,同样糟糕的事情发生了,服务器给客户端发送的同步确认报文丢失了,或者是说有人恶意向服务器不断发送 SYN 同步报文(SYN 洪水)。那么服务器端就会有大量的无效连接,服务器处理连接的数量是有限的,当有大量的无效连接建立后,服务器处理有效连接的能力就会受限,且建立连接会消耗大量是资源,至此有可能导致服务器崩溃。

简单来说两次握手中第一次握手成功可以确定发送端(客户端)有发送的能力,接收端(服务端)有接收的能力且接收端已经确认发送端有发送的能力;第二次握手成功可以确定接收端(服务端)有发送的能力且发送端已经确认接收端有发送及接收的能力,但是这时 服务端并没有确认客户端有没有接收的能力。这就是为什么需要第三次握手的原因。

通过三次握手成功后,可以确认发送端及接收端同时具有发送及接受的能力,这个时候也标志着 TCP 连接建立成功。那有的同学可能有疑问,为什么不是四次握手呢?

四次握手当然可以,但是明明可以三次握手就可以确认的事情,为什么要再浪费一次资源。

一个 TCP 连接上能发起多少个 HTTP 请求

当把三次握手的过程回答给面试官后,面试官会接着问:那你说说一个 TCP 连接可以发送多少个 HTTP 请求?

回答这个问题我们需要区分 HTTP 的版本。

HTTP1.0

一个服务器在发送完一个 HTTP 响应后,会断开 TCP 连接,这就意味着一个 TCP 连接默认情况下只能发送一个 HTTP 请求

HTTP1/1

每次请求都会重新建立和断开 TCP 连接,代价过大,所以在 HTTP1/1 默认开启 TCP 持久连接,除非请求中写明 Connection: close,那么浏览器和服务器之间是会维持一段时间的 TCP 连接,不会一个请求结束就断掉。也就说理论上只要 TCP 不断开连接,一个 TCP 连接可以发送无数个 HTTP 请求。但是 HTTP/1.1 存在一个问题,单个 TCP 连接在同一时刻只能处理一个请求。

HTTP2.0

在 HTTP2 中由于 Multiplexing(多路复用) 特点的存在,多个 HTTP 请求可以在同一个 TCP 连接中并行进行(理论无上限,但是一般浏览器会有 tcp 并发数的限制,这个根据浏览器而异)。

四次挥手

TCP 使用完毕后就要断开连接, 由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向的连接。收到一个 FIN 只意味着这一方向上没有数据流动,一个 TCP 连接在收到一个 FIN 后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

(1)客户端 A 发送一个 FIN,用来关闭客户 A 到服务器 B 的数据传送(报文段 4)。

(2)服务器 B 收到这个 FIN,它发回一个 ACK,确认序号为收到的序号加 1(报文段 5)。和 SYN 一样,一个 FIN 将占用一个序号。

(3)服务器 B 关闭与客户端 A 的连接,发送一个 FIN 给客户端 A(报文段 6)。

(4)客户端 A 发回 ACK 报文确认,并将确认序号设置为收到序号加 1(报文段 7)。

这是因为服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的连接请求后,它可以把 ACK 和 SYN(ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了。

为了便于理解,我们可以把上面的四次挥手的过程比做一对情侣的分手过程:

(1)女生给男生发消息说我不喜欢你了我们分手吧 (2)男生收到女生发的消息后回复一个哭脸表情后自己难过半天 (3)男生对女生发信息说既然你不喜欢我,那我也不喜欢你了,我们分手吧 (4)女生收到男生的消息后回复说你这个钢铁直男分手就分手。

至此两个人成功的和平分手。有同学可能会问,为什么要四次挥手,三次不行吗?

假设上面的过程中去掉(4)女生收到男生的消息后回复说你这个钢铁直男分手就分手,那男生会觉得分手并未完成,虽然分手是女方提出的,但是最后女方没有确认,男方为想是不是还有挽回的余地?于是可能会继续发信息给女方,最后造成不必要的资源浪费,大概流程就是这样。

cookies 、sessionStorage 和 localStorage 的区别

cookies 、sessionStorage 和 localStorage 作为前端三大缓存技术,在面试中出现的概率也十分的高。每种缓存技术有着自己独特的使用场景,所以弄清楚他们之间的异同就显得十分重要。

  • cookie

cookie 就是浏览器储存在用户电脑上的一小段文本文件,cookie 是纯文本格式,不包含任何可执行的代码,通常用作保留用户的登录状态。cookie 工作流程如下:

  1. 浏览器发送请求给服务器;
  2. 服务器设置 cookie 的值;
  3. 浏览器中保存了 cookie 的值。

cookie 的优点

  1. 数据持久性;
  2. 不需要任何服务器资源,因为 cookie 是存储在客户端并发送给服务器读取;
  3. 可配置到期规则,控制 cookie 的生命周期,使之不会永远有效,偷盗者可能拿到的是一个过期的 cookie;
  4. 简单性,基于文件的轻量结构。

cookie 的缺点

  1. 由于 cookie 的实现机制,一旦服务器向客户端发送了设置 cookie 的意图,除非 cookie 过期,否则客户端每次请求都会发送这些 cookie 到服务器端,一旦设置的 cookie 过多,将会导致报头较大。大多数的 cookie 并不需要每次都用上,因为这会造成带宽的部分浪费;
  2. cookie 只能保存 4K 左右的数据量,且大多数浏览器只允许每个站点保存 20 个 Cookie。

上图是百度接口缓存的 cookie 信息

  • sessionStorage

由于 cookie 在使用的时候需要后端去设置要缓存的值,在使用的过程中增加前后端沟通成本,且储存的文件大小过小(一般为 4kb)。而 sessionStorage 完美的解决了 cookie 的缺点。

sessionStorage 的优点

  1. 可以大量保存浏览器中数据,存储大小一般为 5M;
  2. 不会随 http 请求一起发送;
  3. 不同窗口下数据存储相互独立,互不干扰。

sessionStorage 的缺点

  1. 不能存储复杂数据类型(复杂数据类型需要使用 JSON.stringify 进行处理);
  2. 关闭网页后缓存信息失效,是一种短储存。

sessionStorage 的简单使用

​
sessionStorage.name = "蓝桥云课"; // 设置sessionStorage
sessionStorage.name; // 读取sessionStorage
sessionStorage.clear(); // 清除sessionStorage

​

以上是 sessionStorage 在浏览器中的储存位置

  • localStorage

localStorage 和 sessionStorage 很类似,都是浏览器本地缓存,存储大小一般为 5M。和 sessionStorage 不同的是 localStorage 将数据保存在客户端本地的硬件设备(通常指硬盘,也可以是其他硬件设备)中,即使浏览器被关闭了,该数据仍然存在,下次打开浏览器访问网站时仍然可以继续使用。

localStorage 的简单使用

localStorage.name = "蓝桥云课"; // 设置localStorage
localStorage.name; // 读取localStorage
localStorage.clear(); // localStorage

 以上是 localStorage 在浏览器中的储存位置

下面我们来总结下三大缓存技术的异同点,如下所示:

特点cookiesessionStoragelocalStorage
数据生命周期可以指定 maxAge 的值规定 cookie 失效时间,默认关闭浏览器失效关闭浏览器/关闭网站失效除非数据被清理,否则一直存在
存放数据大小4K 左右5M 或者更大5M 或者更大
与服务器通信每次都会携带在 HTTP 头中不参与和服务器通信不参与和服务器通信
易用性需要自己封装 setCookie,getCookie可以直接使用原生接口可以直接使用原生接口

从浏览器输入地址到页面渲染都经历了哪些过程

这是一道比较综合的面试题,答案也不是固定的,从浏览器输入地址到页面渲染经过了很多的过程,且每个过程都可以深挖出很多知识点,面试官可以用这一道题区分出不同面试者的水平。下面我们就来具体学习下本道面试题。

  • 构建请求
// 请求方法是GET,路径为根路径,HTTP协议版本为1.1
GET / HTTP / 1.1;

  1. 查找强缓存

浏览器会先检查是否存在缓存,如果存在缓存就直接从缓存里面拿数据,给到浏览器进行渲染

  1. DNS 解析

由于我们输入的是域名,而数据包是通过 IP 地址传给对方的。因此我们需要得到域名对应的 IP 地址。这个过程需要依赖一个服务系统,这个系统将域名和 IP 一一映射,我们将这个系统就叫做 DNS(域名系统)。得到具体 IP 的过程就是 DNS 解析。 当然,值得注意的是,浏览器提供了 DNS 数据缓存功能。即如果一个域名已经解析过,那会把解析的结果缓存下来,下次处理直接走缓存,不需要经过 DNS 解析

  1. 建立 TCP 连接

建立 TCP 连接经历了下面三个阶段

  • 通过三次握手(即总共发送 3 个数据包确认已经建立连接)建立客户端和服务器之间的连接。
  • 进行数据传输。这里有一个重要的机制,就是接收方接收到数据包后必须要向发送方确认, 如果发送方没有接到这个确认的消息,就判定为数据包丢失,并重新发送该数据包。当然,发送的过程中还有一个优化策略,就是把大的数据包拆成一个个小包,依次传输到接收方,接收方按照这个小包的顺序把它们组装成完整数据包。
  • 断开连接的阶段。数据传输完成,现在要断开连接了,通过四次挥手来断开连接。

TCP 就是通过三次握手确认连接,数据包校验保证数据到达接收方,然后通过四次挥手断开连接保证数据传输的可靠性

  1. 发送 HTTP 请求

现在 TCP 连接建立完毕,浏览器可以和服务器开始通信,即开始发送 HTTP 请求。浏览器发 HTTP 请求要携带三样东西:请求行、请求头和请求体

  1. 网络响应

HTTP 请求到达服务器,服务器进行对应的处理。最后要把数据传给浏览器,也就是返回网络响应。

响应头包含了服务器及其返回数据的一些信息, 服务器生成数据的时间、返回的数据类型以及对即将写入的 Cookie 信息。如果请求头或响应头中包含 Connection: Keep-Alive,表示建立了持久连接,这样 TCP 连接会一直保持,之后请求统一站点的资源会复用这个连接。

  1. 页面渲染

完成以上过程后,数据已经达到浏览器端,接下来就是浏览器解析并渲染数据了

  1. 解析过程

(1) 构建 DOM 树

由于浏览器无法直接理解 HTML 字符串,因此将这一系列的字节流转换为一种有意义并且方便操作的数据结构,这种数据结构就是 DOM 树。DOM 树本质上是一个以 document 为根节点的多叉树

(2) 样式计算

首先,浏览器是无法直接识别 CSS 样式文本的,因此渲染引擎接收到 CSS 文本之后第一件事情就是将其转化为一个结构化的对象,即 styleSheets。 这个格式化的过程过于复杂,而且对于不同的浏览器会有不同的优化策略,这里就不展开了。 在浏览器控制台能够通过 document.styleSheets 来查看这个最终的结构。当然,这个结构包含了以上三种 CSS 来源,为后面的样式操作提供了基础。

(3) 生成布局树

现在已经生成了 DOM 树和 DOM 样式,接下来要做的就是通过浏览器的布局系统确定元素的位置,也就是要生成一棵布局树(Layout Tree)。 布局树生成的大致工作如下:

  • 遍历生成的 DOM 树节点,并把他们添加到布局树中;
  • 计算布局树节点的坐标位置。

值得注意的是,布局树只包含可见元素,对于 head 标签和设置了 display: none 的元素,将不会被放入其中。

  1. 渲染

(1) 构建 DOM 树

浏览器将 HTML 解析成树形结构的 DOM 树,一般来说,这个过程发生在页面初次加载,或页面 JavaScript 修改了节点结构的时候

(2)构建渲染树

浏览器将 CSS 解析成树形结构的 CSSOM 树,再和 DOM 树合并成渲染树

(3)布局(Layout)

浏览器根据渲染树所体现的节点、各个节点的 CSS 定义以及它们的从属关系,计算出每个节点在屏幕中的位置。Web 页面中元素的布局是相对的,在页面元素位置、大小发生变化,往往会导致其他节点联动,需要重新计算布局,这时候的布局过程一般被称为回流(Reflow)。

(4)绘制(Paint)

遍历渲染树,调用渲染器的 paint() 方法在屏幕上绘制出节点内容,本质上是一个像素填充的过程。这个过程也出现于回流或一些不影响布局的 CSS 修改引起的屏幕局部重画,这时候它被称为重绘(Repaint)。实际上,绘制过程是在多个层上完成的,这些层我们称为 渲染层(RenderLayer)

(5)渲染层合成(Composite)

多个绘制后的渲染层按照恰当的重叠顺序进行合并,而后生成位图,最终通过显卡展示到屏幕上。

那什么是渲染层合成呢?

在 DOM 树中每个节点都会对应一个渲染对象(RenderObject),当它们的渲染对象处于相同的坐标空间(z 轴空间)时,就会形成一个 RenderLayers,也就是渲染层。渲染层将保证页面元素以正确的顺序堆叠,这时候就会出现层合成(composite),从而正确处理透明元素和重叠元素的显示。 这个模型类似于 Photoshop 的图层模型,在 Photoshop 中,每个设计元素都是一个独立的图层,多个图层以恰当的顺序在 z 轴空间上叠加,最终构成一个完整的设计图。 对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。

(6)显示器显示内容

栅格化操作完成后,合成线程会生成一个绘制命令,即"DrawQuad",并发送给浏览器进程。 浏览器进程中的 viz 组件接收到这个命令,根据这个命令把页面内容绘制到内存,也就是生成了页面,然后把这部分内存发送给显卡,从而展示在屏幕上。

从浏览器的渲染过程中我们知道,页面 HTML 会被解析成 DOM 树,每个 HTML 元素对应了树结构上的一个 node 节点。而从 DOM 树转化到一个个的渲染层,并最终执行合并、绘制的过程,中间其实还存在一些过渡的数据结构,它们记录了 DOM 树到屏幕图形的转化原理,其本质也就是树结构到层结构的演化。

实验总结

本实验中我们学习了浏览器及 HTTP 相关的知识,特别是从浏览器输入地址到页面渲染都经历了哪些过程,是一道面试中经常考察的面试题,同学们可以用记忆的方式来学习,先记住各个流程都发生了什么事情,然后再逐步理解每个流程经历的过程。在自己的脑中形成一个完整的流程,做到胸有成竹,从容不迫。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王水最甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值