从输入URL到浏览器显示页面过程中都发生了什么?

21,707 阅读8分钟

面试中常被问到的问题,此问题包含web开发中从前端到后端到运维的绝大多数知识,主要考察面试者知识的广度。本文会根据作者了解的程度增加不断更新,不足之处欢迎评论区补充。

浏览器中输入网址。

通过DNS解析域名的实际IP地址

发送至 DNS 服务器并获得域名对应的 WEB 服务器的 ip 地址。

DNS 解析首先会从你的浏览器的缓存中去寻找是否有这个网址对应的 IP 地址,如果没有就向OS系统的 DNS 缓存中寻找,如果没有就是路由器的 DNS 缓存, 如果没有就是 ISP 的DNS 缓存中寻找。 所以,缓存的寻找过程就是: 浏览器 -> 系统 -> 路由器 -> ISP。 如果在某一个缓存中找到的话,就直接跳到下一步。 如果都没有找到的话,就会向 ISP 或者公共的域名解析服务发起 DNS 查找请求。这个查找的过程还是一个递归查询的过程。

检查浏览器是否有缓存

  1. 通过Cache-ControlExpires来检查是否命中强缓存,命中则直接取本地磁盘的html(状态码为200 from disk(or memory) cache,内存or磁盘);
  2. 如果没有命中强缓存,则会向服务器发起请求(先进行下一步的TCP连接),服务器通过EtagLast-Modify来与服务器确认返回的响应是否被更改(协商缓存),若无更改则返回状态码(304 Not Modified),浏览器取本地缓存;
  3. 若强缓存和协商缓存都没有命中则返回请求结果。

与 WEB 服务器建立 TCP 连接。

TCP 协议通过三次握手建立连接。

  • 客户端通过 SYN 报文段发送连接请求,确定服务端是否开启端口准备连接。状态设置为 SYN_SEND;
  • 服务器如果有开着的端口并且决定接受连接,就会返回一个 SYN+ACK 报文段给客户端,状态设置为 SYN_RECV
  • 客户端收到服务器的 SYN+ACK 报文段,向服务器发送 ACK 报文段表示确认。此时客户端和服务器都设置为 ESTABLISHED 状态。连接建立,可以开始数据传输了。

翻译成大白话就是:

  1. 客户端:你能接收到我的消息吗?
  2. 服务端:可以的,那你能接收到我的回复吗?
  3. 客户端:可以,那我们开始聊正事吧。

为什么是3次?:避免历史连接,确认客户端发来的请求是这次通信的人。
为什么不是4次?:3次够了第四次浪费

若协议是https则会做加密

HTTPS = HTTP + 加密 + 认证 + 完整性保护

  1. 要先申请CA证书,并安装在服务器上(一个文件,配置nginx支持监听443端口开启ssl并设置证书路径)
  2. 浏览器发送请求;
  3. 网站从浏览器发过来的加密规则中选一组自身也支持的加密算法和hash算法,并向浏览器发送带有公钥的证书,当然证书还包含了很多信息,如网站地址、证书的颁发机构、过期时间等。
  4. 浏览器解析证书。
    • 验证证书的合法性。如颁发机构是否合法、证书中的网站地址是否与访问的地址一致,若不合法,则浏览器提示证书不受信任,若合法,浏览器会显示一个小锁头。
    • 若合法,或用户接受了不合法的证书,浏览器会生成一串随机数的密码(即密钥),并用证书中提供的公钥加密。
    • 使用约定好的hash计算握手消息,并使用生成的随机数(即密钥)对消息进行加密,最后将之前生成的所有消息一并发送给网站服务器。
  5. 网站服务器解析消息。用已有的私钥将密钥解密出来,然后用密钥解密发过来的握手消息,并验证是否跟浏览器传过来的一致。然后再用密钥加密一段握手消息,发送给浏览器。
  6. 浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。这里浏览器与网站互相发送加密的握手消息并验证,目的是为了保证双方都获得了一致的密码,并且可以正常的加密解密数据,为后续真正数据的传输做一次测试。

下图表示https加密通信的过程:

浏览器发送请求获取页面html

浏览器向 WEB 服务器的 ip 地址发送相应的 http get 请求页面html。

通常的请求行是: 请求的方式(getpost) + 请求的资源的位置(url) + HTTP/[版本号](HTTP/1.1)

发起http请求的过程主要是组装http报文并将报文发向指定地址的过程。

http协议的具体信息可以参考:HTTP介绍教程

服务器响应html

这里的服务器可能是server或者是cdn

注:cdn - 内容分发网络,可用来加快传输速度,主要用来存储静态文件,例如前端的html、css、js、图片文件等。具体请参考:CDN概念基本介绍

服务器上可能会通过nginx等设置静态资源代理,将url对应的html等静态资源返回。

nginx是常用的反向代理服务器,介绍请见:Nginx 入门指南

如果网站是博客或者其他需要seo友好的页面,就需要做服务端渲染,这时服务器会根据模版和数据渲染好html文件返回给前端。

常见的服务端渲染方案有:ejsart-template、等模版语法,也有基于vue、react等框架的服务端渲染框架nuxt.jsnext.js等。

浏览器解析 HTML

  • 浏览器下载 HTML 数据,将html文档解析成为一个个标签,这些标签组成了树状结构
  • 如果解析到style标签则开始解析css,如果解析到link标签则先异步下载,完成后解析css。
  • 如果遇到script标签,判断是行内写法则直接解析执行,如果是src引入则同步下载脚本文件,下载完成立即执行,注意这里下载过程是阻塞的,其他流程都会等下载完成后执行。

浏览器解析HTML文档过程内容较多,详情请看:

浏览器渲染页面

浏览器渲染页面的过程主要是解析html文档组成标签节点树,解析css形成样式规则树,标签节点树和样式规则树共同组成渲染树,浏览器最终显示渲染树形成页面。

  1. 浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。(更具体的解析HTML过程看上一篇博客:点击打开链接)
  2. 将CSS解析成 CSS Rule Tree(css规则树) 。
  3. 解析完成后,浏览器引擎会根据DOM树和CSS规则树来构造 Render Tree。注意:Render Tree 渲染树并不等同于 DOM 树,因为一些像Header或display:none的东西就没必要放在渲染树中了。
  4. 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步进行layout,进入布局处理阶段,即计算出每个节点在屏幕中的位置。
  5. 再下一步就是绘制,即遍历RenderTree,并使用用户界面后端层绘制每个节点。根据计算好的信息绘制整个页面。

注意:上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。

浏览器解析执行js脚本

这个过程中可能会有dom操作、ajax发起的http网络请求等。

浏览器发起网络请求

web-socket、ajax等,这个过程通常是为了获取数据

服务器响应ajax请求

  • ajax请求在到达真正的server之前,可能还会经过网关全线校验、消息队列或nginx等负载均衡处理
  • 到达server后,后端会解析http请求报文,得到url、请求参数、http头、cookie等等信息
  • 登录校验、权限校验(cookie校验、jwt权限校验等)
  • 可能会查询数据库,进行常用的CRUD(增删改查)等操作
  • 返回响应数据

浏览器处理事件循环等异步逻辑。

setTimeout、setInterval、Promise等宏任务、微任务队列

不足之处,欢迎在评论区补充,作者会不断更新