网红面试题:从输入 url 到看到页面发生了什么

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
简介: 从输入 url 到看到页面发生了什么

流程图



这题扎眼看上去没问题,无非是 HTTP 请求到浏览器渲染,但可以聊的东西很多。我想它的执行顺序是,用户输入——开始导航——HTTP请求——浏览器渲染。其中用户输入、开始导航、浏览器渲染是浏览器方面的知识点,HTTP请求是 HTTP 方面的知识点

以下就是从输入 url 到看到页面的整个流程图


image.png

从url输入到页面渲染


前言



了解"开始导航"之前,需要先知道浏览器架构,简单来说,现代浏览器由1个浏览器主进程、1个GPU进程、多个渲染进程、多个插件进程、网络进程、音频进程、存储进程组成

下图是李兵在《浏览器工作原理与实践》[1]中所示,展示 Chrome 浏览器的架构


image.png


以及未来现代浏览器架构示意图:


image.png


文章现代浏览器内部揭秘[2]中有一张图,是这样描述的


image.png


图中表明浏览器主进程包含了 UI 线程、网络线程、存储线程,与李兵的观点有所不同。那以谁为准呢?以时间为准,李兵的专栏是19年所写,而《现代浏览器内部解密》是 18 年的文章,站在 2022 年的背景,现代浏览器,UI、网络、存储等都已升级为进程,而非是浏览器主进程中的线程


用户输入



当用户在地址栏中输入一个字符串时,地址栏会判断输入的关键字是搜索内容,还是请求的URL


  • 如果是搜索内容,地址栏会使用浏览器默认的搜索引擎,合成新的带搜索关键字的URL


  • 例如在chrome中搜长泽雅美

image.png


  • 如果输入内容符合 URL 规则,例如输入azhubaby.com,那么地址栏会根据规则,把这段内容加上协议合成完成的 URL,如 https://azhubaby.com


当用户输入关键字并键入回车之后,意味着当前页面将替换为新的页面,此时浏览器中有个 API——beforeunload[3],它允许页面在离开之前触发是否一个确认对话框。这里使用此API,可让浏览器不再导航


// 监听离开页面前的事件
window.addEventListener('beforeunload', (event) => {
 event.preventDefault();
    event.returnValue = '';
})


可在这里看看 beforeunload 的demo[4]


从浏览器架构分工上讲,当用户输入字符串时是 UI 进程(老一点的浏览器是浏览器主进程)在运作


开始导航



当敲下 Enter 键时,UI 进程将指挥权交接给了网络进程。网络进程接受请求指令前,会先查找本地缓存是否有缓存。如果有缓存该资源,那么直接返回资源给浏览器进程;如果在缓存中没找到该资源,那么则正式进入HTTP请求阶段


关于HTTP缓存方面的知识可以看看这篇——面试常客:HTTP 缓存


HTTP请求



之前写过一篇TCP/IP 协议及网络分层模型,讲述了 TCP/IP 网络分层协议,它就像搭积木一样,每一层需要下一层的支撑,我们的 HTTP 请求是其 HTTP 协议的应用,需要先连接传输层(TCP)以及更底层网络互连层(IP)


image.png


而IP从哪里来,通过 DNS, 使其域名 和 IP 做映射


我们使用倒推法可以理清“路线”:


HTTP 请求 —— HTTP 协议连接 —— TCP 协议连接 —— IP 协议连接 —— 需要知道 IP——DNS 做域名/IP映射


所以进入 HTTP 请求的第一步是 DNS 解析


DNS 解析


这里对 DNS 不做过多概述,简单来说,它的作用是用域名代替 IP 地址,符合人的记忆。输入du.azhubaby.com ,表示 IP 地址 47.102.152.19 ,你可以在命令行中 ping 一个域名,来求证一下结果


image.png

ping域名


HTTP 请求之前的第一步是判断 DNS 中是否有缓存,如果有,直接返回 IP 地址;如果没有,则进行 DNS 解析,并把结果 IP 缓存到 DNS


有了 IP 地址后,IP 层连接成功,接下来就是 TCP 传输层


TCP 连接


这里要看HTTP协议的版本,如果是 HTTP/1.1 的话,就要考虑TCP队列否饱满,因为 HTTP/1.1 最多允许一个域名连接 6 条TCP,太多了就要在等待TCP队列中排队;如果是 HTTP/2 的话,那就没事,它允许TCP并发


这里还要考虑到如果协议是 HTTPS 协议的话,还需要建立一条 TLS 连接


等真正 TCP 连接时,就联想到网红面试题:三次握手、四次挥手


三次握手、四次挥手


为什么是三次握手和四次挥手,因为只有这样才能让双方(客户端和服务端)知道彼此的接收能力和发送能力是没问题的


image.png


步骤为:


  • 客户端提出建立连接,发出客户端seq:seq=client_isn
  • 服务端收到消息后返回 ack=client_isn+1 和服务端seq:seq=server_isn
  • 客户端收到后返回ack=server_isn+1 表示收到了

可以理解为男女双方确认关系,男女双方要结婚,怎么办?先见父母得到父母认同,之前听过这样一句话:得不到父母祝福的婚姻是不幸福的(当然,不见父母直接结婚的也有,但不主流)

  • 男方提出去女方家,带上见面礼seq:seq=男方的诚意
  • 女方家收到见面礼后返回(给男方)红包 ack=我们认可你啦 以及女方去男方家也带上见面礼seq:seq=女方的诚意
  • 男方家收到见面礼后返回(给女方的)红包 ack=server_isn+1

这个叫确定关系。所以要又来又回三次,双方都确保知道对方的诚意和自己的诚意

那什么是四次挥手呢?


在断开之前,需要进行四次挥手


image.png


为什么要有四次挥手?


主要是为了确保双方都知道对方断开连接


具体步骤为:


  • 客户端第一次发送消息给服务端告诉它需要断开连接
  • 服务端收到消息后返回消息告诉客户端:知道了,为了确保服务端收到了之前所有的 HTTP 请求,服务端需要等一等再断开连接
  • 服务端确认所有的HTTP请求都收到了,主动发消息给客户端:我这边所有的请求都处理完了,我也可以断开连接了
  • 客户端收到这个请求后,返回消息告诉服务端:我知道,断开连接吧

主要是为了确认双方的接收能力和发送能力是否正常、制定自己的初始化序列号为后面的可靠性传送做准备

可以理解为一对男女要分手

  • 女方提出分手,说你对我不好,我要分手
  • 男方觉得需求合理,同意分手,但分手之前要把联系方式、合照、各种乱七八糟的事情算清楚再分手
  • 男方理清楚后,主动发消息给女方,说这边都处理清楚了,以后你是你,我是我,我们可以分手了
  • 女方收到消息后,返回告诉男方:我知道了,分手吧


于是乎,它们就断了,分手手续完成。具体详细的信息可看猿人谷的面试官,不要再问我三次握手和四次挥手,一个字:细


发送HTTP请求


TCP连接已经通了,现在正式发送 HTTP 请求,这里又有的聊了,如 HTTP 的报文内容、请求头、响应头、请求方法、状态码等知识点


首先 HTTP 的报文结构由 起始行 + 头部 + 空行 + 实体组成,简单来说就是 header+body,HTTP 的报文可以没有body(get方法),但必须要有 header

请求头由请求行 + 头部字段构成,响应头由状态行 + 头部字段构成


请求行有三部分:请求方法、请求目标和版本号


  • 例如 GET / HTTP/1.1


状态行也有三部分:版本号、状态码和原因字符串


  • 例如 HTTP/1.1 200 OK


在浏览器中,打开F12,在 NetWork 中任何一个请求中,你都会看到这样的结构


image.png


这里我们也常会遇到一些例如 GET 和 POST 请求方式的区别、HTTP 状态码等相关的衍生问题


GET 和 POST 请求方式的区别


  • 从缓存角度看,GET 会被缓存,POST 不会被缓存
  • 从参数角度看,GET 通过在 URL 的"?"后以 key=value 方式传参,数据之间以“&”相连接;POST 则要将数据封装到请求体中发送,这个过程不可见
  • 从安全角度看,GET 不安全,因为 URL 可见;POST 较 GET 安全度高
  • 从编码角度看,GET 只接受 ASCII 字符,向服务器发送中文字符可能会出现乱码;POST 支持标准字符集,可以正确传递中文
  • 从数据长度的限制看,GET 一般受 URL 长度限制(URL 的最大长度是 2048 个字符),POST 无限制


HTTP 状态码


RFC 标准把状态码分成了五类 ,用数字的第一位表示分类,而 0~99 不用,这样状态码的实际可用范围就大大缩小了,由 000~999 变成了 100~599。


这五类的具体含义是:


  • 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
  • 2××:成功,报文已经收到并被正确处理;
  • 3××:重定向,资源位置发生变动,需要客户端重新发送请求;
  • 4××:客户端错误,请求报文有误,服务器无法处理;
  • 5××:服务器错误,服务器在处理请求时内部发生了错误。


目前 RFC 标准里总共有 41 个状态码


101 - Switching Protocols,客户端使用 Upgrade 头字段


200 - 请求成功


204 - 无内容,服务器成功处理了请求,但没有返回任何内容。


206 - 一般用来做断点续传,或者是视频文件等大文件的加载


301 - 永久重定向


302 - 临时重定向


304 - 未修改协商缓存,返回缓存中的数据。它不具有通常的跳转含义,但可以理解成 重定向到缓存的文件(即缓存重定向)


400 - 请求中语法错误


401 - 未授权


403 - 服务器收到请求,但是拒绝提供服务,即资源不可用


404 - 无法找到请求资源


408 Request Timeout - 请求超时


414 - 请求 URI 过长(如图一新浪常有)


500 - 服务器内部错误


501 - 尚未实施:服务器不具备请求功能


502 - 网关错误


503 - 服务器不可用,主动用503响应请求或 Nginx 设置限速,超过限速,会返回503


504 - 网关超时


这里要对 304 做一下说明,当请求头 If-Modified-SinceIf-None-Match  中判断修改时间是否一致(或唯一标识是否一致),是,则返回304,使用浏览器内存中的本地缓存;不一致则说明要更新,继续请求资源放回给客户端,并带上 Last-ModifiedETag


请求方式


HTTP/1.1 规定了八种方法,都必须是大写形式


  • GET:获取资源,可以理解为读取或者下载数据。只有GET请求才能起到缓存效果
  • HEAD:获取资源的元信息
  • POST:像资源提交数据,相当于写入或上传数据
  • PUT:类似 POST
  • DELETE:删除资源
  • CONNECT:建立特殊的连接隧道
  • OPTIONS:列出可对资源实行的方式
  • TRACE:追踪请求 - 响应的传输路径


浏览器渲染



当HTTP 请求完毕后,断开 TCP 连接,将资源返回给客户端(浏览器)。此时浏览器要判断是否与打开的网站是同一个站点。因为如果是同一个站点的话,则可使用同站点的渲染进程渲染页面,如果不是,浏览器则打开新的渲染进程解析资源


浏览器渲染的大致流程如下图所示:


image.png


我们可以将页面渲染分为三个步骤:


解析


  • HTML 被解析为 DOM 树,CSS 被解析为 CSS 规则树,JavaScript 通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree


渲染


  • 浏览器引擎通过 DOM Tree 和 CSS Rule Tree 构建 Rendering Tree(渲染树),这其中进行大量的 回流(Reflow) 和 重绘(Repaint)


  • 回流和重绘


  • 回流:意味着元件的几何尺寸变了,需要重新验证并计算 Render Tree
  • 重绘:屏幕的一部分需要重画,比如某个CSS 的背景色变了,但元件的几何尺寸没有变
  • 回流的成本要比重绘大


绘制


  • 最后通过操作系统(浏览器)的Native GUI的API绘制


其中,衍生出重绘和回流的问题,提高性能的方法之一就是减少浏览器的渲染时间,其中的一个优化点就是减少重绘和回流


减少回流和重绘的方法


  1. 不要一条条修改 DOM 样式,与其这样,不如预定义好CSS的class,然后修改DOM的样式


  1. 把DOM“离线”后修改


  1. 使用 documentFragment 对象在内存里操作 DOM
  2. 先把 DOM 给 display:none(有一次 Reflow),然后你想怎么改就怎么改,再把它显示出来
  3. clone 一个 DOM 节点到内存里,然后想怎么改就怎么改,改完后和在线的那个交换一下


  1. 不要把 DOM 节点的属性值放在一个循环中当作循环的变量,不然这会导致大量地读写这个节点的属性


  1. 尽可能地修改层级比较低的DOM


  1. 不要使用 table 布局


造成回流的属性:


width、height、padding、margin、border、position、top、left、bottom、right、float、clear、text-align、vertical-align、line-height、font-weight、font-size、font-family、overflow、white-space


造成重绘的属性:


color、border-style、border-radius、text-decoration、box-shadow、outline、background


记住一点,回流是与几何大小相关,重绘与大小无关


如此,从输入 url 到看到页面的整个流程就走完了


总结



这道题能衍生很多问题,从一题可以测试出面试者的HTTP、浏览器相关知识。正所谓”鹏怒而飞,其翼若垂天之云;水击三千里,碧空九万丈;好风凭借力,送我上青云。“。这道题之所以能成为经典题,不是没有它的原因的


笔者这里做一个总结,把这题可以衍生的知识点逐一列出,待君思索


浏览器方面


  • 浏览器架构


  • 由什么组成?浏览器主进程、GPU进程、多个渲染进程、多个插件进程、网络进程、音频进程、存储进程等
  • 渲染进程中有哪些进程?GUI渲染线程、JS 引擎线程、事件触发线程、网络异步线程、定时器线程
  • 进程和线程的区别?进程是应用程序创建的实例,而线程依托于进程,它是计算机最小的运行单位


  • 浏览器渲染


  • 两者的区别
  • 重绘和回流的属性
  • 如何减少重绘和回流,提高渲染性能
  • 渲染流程?解析、渲染、绘制
  • 重绘和回流


HTTP方面


  • HTTP缓存


  • HTTP/1.1 ETag/If-None-Match
  • HTTP/1.0 Last-Modified/If-Modified-Since
  • 精准度:ETag > Last-Modified
  • 性能:Last-Modified > ETag
  • HTTP/1.1 Cache-Control
  • HTTP/1.0 Expires
  • Cache-Control > Expires
  • 强缓存
  • 协商缓存


  • TCP/IP 连接


  • 三次握手、四次挥手


  • 网络层面的性能优化


  • HTTP/1.1的做法
  • HTTP/2 的做法
  • HTTP/3 的做法
  • 每个阶段采用的性能优化是有所不同的


参考资料



  • 浏览器的渲染原理简介[5]



  • 万字详文:深入理解浏览器原理[6]



  • 前端都该懂的浏览器工作原理[7]


[1] 《浏览器工作原理与实践》: https://time.geekbang.org/column/intro/100033601?tab=intro


[2] 现代浏览器内部揭秘: https://juejin.cn/post/6844903692890537992


[3] beforeunload: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/beforeunload_event


[4] demo: https://azhubaby.com/demo/beforeunload.html


[5] 浏览器的渲染原理简介: https://coolshell.cn/articles/9666.html


[6] 万字详文:深入理解浏览器原理: https://zhuanlan.zhihu.com/p/96986818?tdsourcetag=s_pctim_aiomsg


[7] 前端都该懂的浏览器工作原理: https://segmentfault.com/a/1190000022633988

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
16天前
|
缓存 网络协议 JavaScript
面试常考题:输入url到页面渲染发生了什么?(前半段)
面试常考题:输入url到页面渲染发生了什么?(前半段)
|
16天前
|
JavaScript 前端开发 网络协议
面试常考题: 输入url到页面渲染发生了什么(后半段)
面试常考题: 输入url到页面渲染发生了什么(后半段)
|
2月前
|
缓存 网络协议 前端开发
【高频】从输入URL到页面展示到底发生了什么?
【高频】从输入URL到页面展示到底发生了什么?
|
2月前
|
Web App开发 移动开发 安全
如何做到修改 url 参数页面不刷新
如何做到修改 url 参数页面不刷新
|
3月前
|
缓存 网络协议 前端开发
URL输入到页面渲染过程详解
URL输入到页面渲染过程详解
29 1
|
3月前
|
JavaScript
js如何实现修改URL参数并不刷新页面
js如何实现修改URL参数并不刷新页面
|
3月前
|
JavaScript
如何在JS中实现修改URL参数而不刷新页面
如何在JS中实现修改URL参数而不刷新页面
|
3月前
uView queryParams 对象转URL参数
uView queryParams 对象转URL参数
46 0
|
3月前
|
JavaScript
vue截取URL中的参数
vue截取URL中的参数
46 0
|
5天前
|
开发框架 前端开发 .NET
Asp.net Webapi 的 Post 方法不能把参数加到 URL 中?试试这样写
Asp.net Webapi 的 Post 方法不能把参数加到 URL 中?试试这样写