【offer 收割机之面试必备】一篇非常全面的 从 URL 输入到页面展现的全过程 精华梳理

本文最后更新于:2022年4月4日 上午

🧨 大家好,我是 Smooth,一名大二的 SCAU 前端er
🏆 本篇文章是我在复习该知识点时,查看了多篇文章之后,结合我自己的个人思考与理解汇聚而成的精华
🙌 如文章有误,恳请评论区指正,谢谢!
❤ 写作不易,觉得有帮助的可以 转发 支持,谢谢支!

原文章链接

正文开始前你需知道的

从输入URL到页面显示不仅仅是一道经典的面试题,这个知识点中涉及到了非常广泛的知识点,因此面试官可以通过这个问题有点到面的向候选人发起提问,来看看面试者在计算机网络和浏览器这方面知识的广度和深度。

废话不多说,下面就开始吧!


文章目录一览

  1. 解析用户输入内容(关键字还是 URL)
  2. 看是否命中强缓存(没有则继续下一步)
  3. DNS 解析(找到服务器的 IP 地址)
  4. 建立 TCP 连接(三握)
  5. 发送 HTTP 请求(先看是否命中协商缓存,有则 304,没有则 200 和新资源)并接收对应响应报文
  6. 关闭 TCP 连接
  7. 提交文档阶段
  8. 浏览器渲染

一、用户输入阶段

用户在地址栏输入内容之后,浏览器会首先判断用户输入的是合法的URL还是搜索内容,如果是搜索内容就合成URL,如果是合法的URL就开始进行加载。

在这里,要明确我们具体要查找的东西到底是什么

搜索关键字

我们要搜索一些内容,例如去百度搜索引擎进行百度查找某个问题的答案,那么浏览器就会自动调用默认搜索引擎进行关键字的查找

  • 这个流程需要对输入的不安全字符编码进行转义(安全字符指的是数字、英文和少数符号),使用的编码是 UTF-8 编码。因为URL的参数是不能有中文的,也不能有一些特殊字符,比如= ? &,否则当我搜索1+1=2,假如不加以转义,url会是/search?q=1+1=2&source=chrome,和URL本身的分隔符=产生了歧义。

  • URL对非安全字符转义时,使用的编码叫百分号编码,因为它使用百分号加上两位的16进制数表示。这两位16进制数来自UTF-8编码,将每一个中文转换成3个字节,比如我在google地址栏输入“中文”,url会变成/search?q=%E4%B8%AD%E6%96%87,一共6个字节。

  • 我们在写代码时经常会用的encodeURIencodeURIComponent正是起这个作用的,它们的规则基本一样,只是= ? & ; /这类URI组成符号,这些在encodeURI中不会被编码,但在encodeURIComponent中统统会。因为encodeURI是编码整个URL,而encodeURIComponent编码的是参数部分,需要更加严格把关。

搜索关键字阶段参考的是 @前端年年 大佬的这篇文章,链接在此

域名解析对应的 IP

如果是合法的 URL,说明我们想通过该 URL(统一资源定位符) 查找到对应服务器上的该资源,那么要查找的实质就是 该域名解析后所对应的 IP 地址,即 域名与 IP 地址的一个映射关系

后面篇幅重点讲到的都是第二种情况,后续篇幅中我将其简称为 映射关系



二、查找强制缓存

在有效期内的缓存资源直接使用,称之为强缓存,从 chrome 网络面板看到这类请求直接返回200,size 是 memory cache 或者 disk cachememory cache 是指从资源从内存中被取出,disk cache 是指从磁盘中被取出;从内存中读取比从磁盘中快很多,但资源能不能分配到内存要取决于当下的系统状态。通常来说,刷新页面会使用内存缓存,关闭后重新打开会使用磁盘缓存。

  • 浏览器首次加载资源成功时,服务器返回 200,此时浏览器不仅将资源下载下来,而且把 response 的 header(里面的 date 属性非常重要,用来计算第二次相同资源时当前时间和 date 的时间差)一并缓存;

  • 下一次加载资源时,首先要经过强缓存的处理。强缓存是利用 http 头中的 Expires 和 Cache-Control 两个字段来控制的。强缓存中,当请求再次发出时,浏览器会根据其中的 Expires 和 Cache-Control 判断目标资源是否“命中”强缓存,若命中则直接从缓存中获取资源,不会再与服务端发生通信。其中 Cache-Control 的优先级最高,如果 Cache-Control:no-cache,就直接进入到协商缓存的步骤了,如果 Cache-Control:max-age=xxx,就会先比较当前时间和上一次返回 200 时的时间差,如果没有超过 max-age,命中强缓存,不发请求直接从本地缓存读取该文件(这里需要注意,如果没有 Cache-Control,会取 Expires 的值,来对比是否过期),过期的话会进入下一个阶段,协商缓存,这个后面再提到。



三、DNS 解析

DNS 解析目的是找到目标服务器的 IP 地址,才能进行后续的协商缓存验证或真实的从服务器拿到所需数据

  1. 先找浏览器本地的缓存

  2. 找操作系统 hosts 文件的缓存

  3. 以上两步都没找到需要的资源,就要进行网络请求啦,开始跟外界打交道,去本地 DNS 服务器(local DNS)进行查找,如果本地 DNS 服务器的缓存中已经存在该映射关系,那么直接返回,否则继续进行后续步骤(99% 的 DNS 解析到这一步就结束了,因为一般 local DNS 中存在大量映射关系缓存)。

  4. 本地 DNS 服务器作为代理服务器,向它上面的根域名服务器建立 UDP 连接后发出请求,根域名服务器返回查询域的主域名服务器(即 gTLD,像 .COM.CN 这种顶级域名)。

  5. 本地 DNS 服务器拿到后向 gTLD 发请求,gTLD 是可以找到你想查找域名的 Name Server 地址的,本地 DNS 服务器向 Name Server 地址发送请求,拿到该域名对应的 IP 和 TTL(time to live,即域名解析结果在DNS服务器中存活的时间),然后将结果先是自己做一个缓存(根据 TTL 设置映射存活时间),然后返回给浏览器,DNS 解析结束

Name Server 概念
服务商提供的服务器地址,比如你在阿里云注册的域名,那查找就是去阿里云的服务器查,因为你是去域名提供商的服务器发请求,那肯定是能拿到对应的ip地址的


四、建立 TCP 连接

首先会等待 TCP 队列

chrome 有个机制,同一个域名同时最多只能建立6个TCP连接,如果超过这个数量的连接必须要进入排队等待状态。

知识巩固
对于多路复用,http 1.1 采取建立多个 TCP 连接,http 2.0 采用建立一个 TCP 连接并行发起多个请求


正式开始建立 TCP 连接

通过TCP三次握手与服务器建立连接,然后进行数据传输。

image.png

第一次握手: 建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;

第二次握手: 服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;

第三次握手: 客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

A:我要跟你建立连接,你那边接受得到我的请求吗?
B:接收到啦!没问题,但得向你确认下,证明这是你真实的要准备跟我建立的连接,而不是你很久之前发过的
A:对,没问题,这是我刚发给你的



为什么要三次握手?两次可以吗?

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

具体例子如下

已失效的连接请求报文段 的产生在这样一种情况下:client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在 client 并没有发出新的建立连接请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 serve r却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。”

四次握手可以吗?

可以但没必要

四次握手只是将第二次握手分解为了以下两个步骤

  1. 先发送确认位 ACK = 1,然后确认号 ack = x + 1
  2. 再发送同步位 SYN = 1,和序号 seq = y


    五、发送 HTTP 请求并接收相应结果

先看是否命中协商缓存

  • 有则返回状态码 304 并更新资源标识符
  • 没有则返回状态码 200 和新资源

超过有效期的,则携带缓存的资源标识向服务端发起请求,校验是否能继续使用,如果服务端告诉我们,可以继续使用本地存储,则返回 304,并且不携带数据;如果服务端告诉我们需要用更新的资源,则返回 200,并且携带更新后的资源和资源标识缓存到本地,方便下一次使用。

然后接收对应响应报文

服务器首先返回相应行,包括协议版本和状态码,然后会返回响应头包含返回的数据类型,服务器要在客户端保存的 Cookie 等,一般来说是返回 HTMLCSSJSImage 文件

对于是否命中协商缓存

  • 协商缓存阶段,则向服务器发送 header 带有 If-None-Match 和 If-Modified-Since 的请求,前者优先级大于第二个,所以先讲第一个对应关系 请求头的 If-None-Match 和 响应头的 Etag。服务器会比较这两个字段值,如果相同,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200。

  • 协商缓存第二个对应关系是 If-Modified-SinceLast-modified,如果客户端发送的 If-Modified-Since 的值跟服务器端获取的文件最近改动的时间,一致则命中协商缓存,返回 304;不一致则返回新的 Last-modified 和文件并返回 200;

为什么协商缓存中 Etag 优先级大于 Last-modified ?

因为后者是标识着资源的最后修改时间(不准确,因为修改了文件并不代表文件内容发生改变,可能改变后又撤销了),前者可以理解为是一个资源唯一标识符,是服务器通过内置算法根据文件内容生成的 hash 值,所以更准确,当然,因为计算所以性能消耗更大,不太推荐使用 Etag

拓展知识

什么是启发式缓存,在什么条件下触发?

启发式缓存:

如果响应中未显示 ExpiresCache-Control:max-ageCache-Control:s-maxage,并且响应中不包含其他有关缓存的限制,缓存可以使用启发式方法计算新鲜度寿命。通常会根据响应头中的2个时间字段 Date 减去 Last-Modified 值的 10% 作为缓存时间。

1
2
3
4
// Date 减去 Last-Modified 值的 10% 作为缓存时间。

// Date:创建报文的日期时间, Last-Modified 服务器声明文档最后被修改时间
response_is_fresh = max(0,(Date - Last-Modified)) % 10

看到这里是不是感觉有点累了?坚持住!后面还有更丰富的知识等着你去探索!


六、关闭 TCP 连接

数据传输完成后,通过四次挥手来断开连接。

当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的啊。那对于TCP的断开连接,这里就有了神秘的“四次挥手”。

image.png

第一次挥手: 主机1(可以使客户端,也可以是服务器端),设置Sequence Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;

第二次挥手: 主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;

第三次挥手: 主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;

第四次挥手: 主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

A:我要断开连接啦
B:好的,你先断开,等我把我这边的数据传完给你我再断
过了一会儿,等B传完后
B:我传完啦,我也可以断开跟你的连接了,听到了吗
A:知道你也断开连接啦,你先断,我过 2MSL 再断,不然怕你听不见我跟你说的话



为什么要四次挥手?

TCP 协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP 是全双工模式,这就意味着,当主机1发出FIN 报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回 ACK 报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了 FIN 报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么要等待 2MSL?

MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。
原因有二:

  • 保证TCP协议的全双工连接能够可靠关闭
  • 保证这次连接的重复数据段从网络中消失

第一点:如果主机1直接 CLOSED 了,那么由于 IP 协议的不可靠性或者是其它网络原因,导致主机2没有收到主机1最后回复的 ACK。那么主机2就会在超时之后继续发送 FIN,此时由于主机1已经 CLOSED 了,就找不到与重发的 FIN 对应的连接。所以,主机1不是直接进入 CLOSED,而是要保持 TIME_WAIT,当再次收到FIN的时候,能够保证对方收到 ACK,最后正确的关闭连接。

第二点:如果主机1直接 CLOSED,然后又再向主机2发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达主机2,由于新连接和老连接的端口号是一样的,TCP 协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以 TCP 连接还要在 TIME_WAIT 状态等待2倍 MSL,这样可以保证本次连接的所有数据都从网络中消失。

关于三握四挥的内容,在谢希仁的《计算机网络》一书中讲的非常透彻,有时间的可以进行查阅



七、提交文档阶段

  1. 网络进程将获取的数据进行解析,根据响应头中的 Content-type 来判断响应数据的类型,如果是字节流类型,就将该请求交给下载管理器去下载,如果是 text/html 类型,就通知浏览器进程获取到的是 HTML,准备渲染进程。

  2. 一般情况下浏览器的一个 tab 页面对应一个渲染进程,如果从当前页面打开的新页面并且属于同一站点,这种情况会复用渲染进程,其他情况则需要创建新的渲染进程。

  3. 渲染进程准备好之后,浏览器会发出提交文档的消息给渲染进程,渲染进程收到消息后,会和网络进程建立数据传输的管道(IPC),文档数据传输完成后,渲染进程会返回确认提交的消息给浏览器进程

  4. 浏览器收到确认提交的消息后,会更新浏览器的页面状态,包括了安全状态,地址栏的URL,前进后退的历史状态,并更新 web 页面为空白

有需要的小伙伴可以了解一下 安全沙箱站点隔离 的概念



八、浏览器渲染阶段

前置知识

  • 在浏览器获取到 HTML 文件后,由于无法直接理解与使用 HTML,所以要先将他转换为能够读懂的 DOM 树结构

  • CSS 文件一样没法被浏览器直接理解,所以首先把 CSS 解析成样式表。这三类样式都会被解析:

    • 通过 link 引用的外部 CSS 文件(外联)
    • <style>标签内的样式(内联)
    • 元素的 style 属性内嵌的 CSS(行内样式)

开始介绍

  1. 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构
  2. 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,并计算出 DOM 节点样式后,生成 CSS 树
  3. 浏览器根据 DOM 树与 CSS 树生成 render 树(渲染树)
  4. 布局阶段(layout):浏览器根据 render 树生成 layout tree(布局树),在布局树中,DOM 树上所有不可见节点都没加上去(比如 display: none 的元素)。layout tree 上会显示出各个节点的坐标位置以及宽高
  5. 绘制阶段(painting):接着会根据 layout tree 生成 layer tree(图层树),它是根据你的不同节点所对应的层级关系来生成的。并根据你的 layer tree 去生成 painting 表,它记录了绘制图层的指令和步骤。

image.png

  1. 光栅化操作:此时会将 paint 表 commit 到渲染进程的合成线程中去操作。

image.png

  1. 接着浏览器会合并合各个图层,将数据由 CPU 输出给 GPU 最终绘制在屏幕上。(复杂的视图层会给这个阶段的 GPU 计算带来一些压力,在实际应用中为了优化动画性能,我们有时会手动区分不同的图层)。
  2. 最后,合成完后,合成线程会发送一个指令给浏览器,告诉它已完成,让浏览器显示页面

至此,我们已经分析完了整个渲染流程,从 HTML 到 DOM、样式计算、布局、图层、绘制、光栅化、合成和现实

该阶段推荐阅读此文章,更详细,点击跳转

关于页面渲染阻塞

由于浏览器解析并渲染 DOM 元素占用的是主线程,对于图片、CSS 等文件在下载时不会阻塞浏览器渲染,但 JS 就不一样了,浏览器遇到 <script> 标签引入的 JS 时,会停止渲染,等 JS 文件下载并执行完后,才将主线程控制器归还给浏览器进行继续渲染

导致的问题

由上面描述可知,浏览器渲染(布局和绘制) 和 JS 文件的处理都要占用主线程,但如果 JS 文件特别大,下载和执行占用的时间非常长,我们都知道一个知识点,当页面以每秒60帧的频率刷新,才不会让用户感受到页面卡顿。在浏览器要绘制下一帧页面时,无法及时将浏览器主线程控制权归还,那么就会导致无法及时绘制下一帧的问题,这时对于我们用户来说的直观感受就是,出现页面卡顿

每一帧绘制结束后,还有剩余时间

image.png

当 JS 过大

image.png


有什么解决方案呢?

可以先自己思考,过一段时间后再去查看后面的 RQ1 获得解决方案

关于浏览器渲染过程,推荐观看 此视频


对于上述八大阶段的一些补充

如果在建立 TCP 连接后,有安全传输需求的,那就要建立 https 安全层,即进行 TLS 握手

协商加密密钥——TLS握手

为了保障通信的安全,我们使用的是 HTTPS 协议,其中的 S 指的就是 TLS。TLS 使用的是一种 非对称 + 对称 的方式进行加密。

  • 对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。这种加密方式速度很快,但是问题在于如何让双方知道秘钥。因为 传输数据都是走的网络,如果将秘钥通过网络的方式传递的话,秘钥被截获,就失去了加密的意义。

  • 非对称加密,每个人都有一把公钥和私钥,公钥所有人都可以知道,私钥只有自己知道,将数据用公钥加密,解密必须使用私钥。这种加密方式就可以完美解决对称加密存在的问题,缺点是速度很慢。

我们采取非对称加密的方式协商出一个对称密钥,这个密钥只有发送方和接收方知道的密钥,流程如下:

  1. 客户端发送一个随机值以及需要的协议和加密方式;
  2. 服务端收到客户端的随机值,发送自己的数字证书,附加上自己产生一个随机值,并根据客户端需求的协议和加密方式使用对应的方式;
  3. 客户端收到服务端的证书并验证是否有效,验证通过会再生成一个随机值,通过服务端证书的公钥去加密这个随机值并发送给服务端;
  4. 服务端收到加密过的随机值并使用私钥解密获得第三个随机值,这时候两端都拥有了三个随机值,可以通过这三个随机值按照之前约定的加密方式生成密钥,接下来的通信就可以通过该对称密钥来加密解密;

通过以上步骤可知,在 TLS 握手阶段,两端使用非对称加密的方式来通信,但是因为非对称加密损耗的性能比对称加密大,所以在正式传输数据时,两端使用对称加密的方式



问题汇总

A & Q1:浏览器渲染卡顿的解决方法

1. 可以通过 requestAnimationFrame() 来解决

这是浏览器的官方 API,此方法会在每一帧被调用,通过 API 的回调,我们可以把 JS 运行任务分成一些更小的任务快(分到每一帧),在每一帧时间用完前暂停 JS 执行,归还主线程,这样的话在下一帧开始时,主线程就可以按时执行布局和绘制

React 最新的渲染引擎 React Fiber 就是用到了这个 API 做了很多优化(时间分片)

image.png

image.png

2. 为 <script> 标签加上 asyncdefer 属性

  • async:异步执行,当浏览器在渲染时,如果遇到 <script> 对应的 JS 文件可同时进行文件下载与浏览器渲染,即并行。当下载结束后,立刻停止浏览器渲染,执行完 JS 后,再继续渲染

  • defer:延迟执行,如果遇到 <script> 对应的 JS 文件也可同时进行文件下载与浏览器渲染,即并行。只不过下载结束后,不会立刻停止浏览器渲染,而是等浏览器全部页面布局绘制完成,才执行 JS 文件

3. 这里就要提到 CSS 中的一个动画属性 transform

由于栅格化的整个流程是不占用主线程的,只在下面的 合成器线程 + 栅格线程中执行,意味着它无需和 JS 抢夺主线程,我们如果反复进行重排和重绘,可能会导致掉帧,这是因为有可能 JS 执行阻塞了主线程,而经 transform 实现的动画不会经过布局和绘制,而是直接运行在合成器线程和栅格线程,所以不会受到主线程中 JS 执行的影响,所以节省了很多时间,减轻了主线程的压力。

image.png


A & Q2:CSSOM 渲染会不会阻塞 DOM 渲染? 会不会阻塞 DOM 树建立?

会,不会。

上文提到页面渲染是渲染进程的任务,这个渲染进程中又细分为 GUI 渲染线程和 JS 线程。

  • 解析 HTML 生成 DOM 树,解析 CSS 生成样式表以及后面去生成布局树、图层树都是由 GUI 渲染线程去完成的,这个线程可以一边解析 HTML,一边解析 CSS,这两个是不会冲突的,所以也提倡把CSS在头部引入。

  • 但是在 JS 线程执行时,GUI 渲染线程没有办法去解析 HTML,这是因为 JS 可以操作 DOM,如果两者同时进行可能引起冲突。如果这时 JS 去修改了样式,那此时 CSS 的解析和 JS 的执行也没法同时进行了,会先等 CSS 解析完成,再去执行 JS,最后再去解析 HTML。

即 CSS 异步下载和解析不会阻塞 DOM 树的构建。但由于 JS 和 CSS 解析不能同时进行(不然会有冲突),所以得等 CSS 解析完 JS 才执行,才继续进行 DOM 渲染,即间接影响。

类似于 JS 的 async、defer 优化

就像 async 或 defer 属性使 script 元素不阻塞解析一样,外部的样式表也可以通过 media 属性 使其不阻塞渲染。使用 media 属性值,浏览器可以智能地决定何时去加载样式表


A & Q3:页面渲染优化的方法

  • HTML文档结构层次尽量少,最好不深于六层;
  • 脚本尽量后放,放在前即可;
  • 少量首屏样式内联放在标签内;
  • 样式结构层次尽量简单;
  • 在脚本中尽量减少DOM操作,尽量缓存访问DOM的样式信息,避免过度触发回流;
  • 减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;
  • 动画尽量使用在绝对定位或固定定位的元素上;
  • 隐藏在屏幕外,或在页面滚动时,尽量停止动画;
  • 尽量缓存DOM查找,查找器尽量简洁;
  • 涉及多域名的网站,可以开启域名预解析

A & Q4:强缓存和协商缓存发生在那个阶段?

强缓存和协商缓存发生在发起 URL 请求阶段,在这个阶段构建请求行之后会查找缓存。

A & Q5:DNS解析中端口需要DNS解析吗?

不需要,因为 HTTP 默认的是80端口,HTTPS 默认的是443端口,如果要指定端口可以直接在 URL 里面添加。

A & Q6:上述哪些阶段可以优化?

1. 优化 DNS 查询:DNS 预解析

前端的 DNS 优化,可以在 html 页面头部写入 DNS 缓存地址,比如

1
2
<meta http-equiv="x-dns-prefetch-control" content="on" />
<link rel="dns-prefetch" href="http://bdimg.share.baidu.com" />

2. 优化TCP连接:可以通过请求头 keep-alive 来优化。

1
keep-alive: connection

在本次 TCP 请求结束后,不主动断开,下次还需要 TCP 连接时就省了,直接在这个 TCP 管道进行传输即可

即节省了进行三次握手的建立 TCP 连接过程

3. 优化 HTTP 响应报文:通过 CDN 和 Gzip 压缩。



A & Q7:常见 http 请求报文头有哪些?

  • User-Agent 浏览器类型
  • Content-Type 报文类型
  • Connection 完成传输是否关闭 TCP 连接
  • Host 访问主机域名
  • Content-Length 内容长度
  • Accept 允许接收的数据类型
  • Accept-Language 允许接收的语言
  • Cookie 用户标识符
  • cache-control 强缓存限制条件,存活时间
  • expires 强缓存限制条件,被上面的替代了
  • etag 协商缓存限制条件,过期的时刻
  • last-modified 协商缓存限制条件,最后修改时间
  • date 时间

等等,还有很多,就不一一列举了


最后

我是 Smoothzjc,致力于产出更多且不仅限于前端方面的优质文章

大家也可以关注我的公众号 @ Smooth前端成长记录,及时通过移动端获取到最新文章消息!

写作不易,「点赞」+「收藏」+「转发」 谢谢支持❤

往期推荐

《都2022年了还不考虑来学React Hook吗?6k字带你从入门到吃透》

《一份不可多得的 Webpack 学习指南(1万字长文带你入门 Webpack 并掌握常用的进阶配置)》

《通过 React15 ~ 17 的优化迭代来简单聊聊 Fiber》

《【offer 收割机之手写系列】10分钟带你掌握原理并手写防抖与节流的立即/非立即执行版本》

《【offer 收割机之 CSS 回顾系列】请你解释一下什么是 BFC ?他的应用场景有哪些?》

《Github + hexo 实现自己的个人博客、配置主题(超详细)》

《10分钟让你彻底理解如何配置子域名来部署多个项目》

《一文理解配置伪静态解决 部署项目刷新页面404问题

《带你3分钟掌握常见的水平垂直居中面试题》

《【建议收藏】长达万字的git常用指令总结!!!适合小白及在工作中想要对git基本指令有所了解的人群》

《浅谈javascript的原型和原型链(新手懵懂想学会原型链?看这篇文章就足够啦!!!)》

参考资料

前端进阶|重学「从URL输入到页面渲染」

史上最详细的经典面试题 从输入URL到看到页面发生了什么?

阿里面试官的”说一下从url输入到返回请求的过程“问的难度就是不一样!


作者:Smooth

文章链接:http://example.com/2022/04/01/%E3%80%90offer%20%E6%94%B6%E5%89%B2%E6%9C%BA%E4%B9%8B%E9%9D%A2%E8%AF%95%E5%BF%85%E5%A4%87%E3%80%91%E4%B8%80%E7%AF%87%E9%9D%9E%E5%B8%B8%E5%85%A8%E9%9D%A2%E7%9A%84%20%E4%BB%8E%20URL%20%E8%BE%93%E5%85%A5%E5%88%B0%E9%A1%B5%E9%9D%A2%E5%B1%95%E7%8E%B0%E7%9A%84%E5%85%A8%E8%BF%87%E7%A8%8B%20%E7%B2%BE%E5%8D%8E%E6%A2%B3%E7%90%86/

版权说明:本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!