前端浏览器输入URL后发生什么?个人笔记

目录
文章目录隐藏
  1. DNS 域名解析
  2. 建立 TCP 链接
  3. 发送 HTTP 请求
  4. 服务器处理请求
  5. 返回响应结果
  6. 关闭 TCP 连接
  7. 浏览器解析 HTML 并渲染布局
  8. 结语

该题是一道特别经典的面试题了,涉及到前端人员应该掌握的基础网络知识,相信很多前端小伙伴都了解。网上也有很多相关文章介绍这方面的知识,我呢趁着最近项目不忙,就自己做了一篇笔记,这篇笔记是我这两天看了数十篇文章总结出来的,感觉比之前理解更透彻了,总结就是一个学习的过程,希望我的理解对大家有帮助。

浏览器输入 URL 之后大致有这么几个阶段:

  • DNS 域名解析
  • 建立 TCP 连接
  • 发送 HTTP 请求
  • 服务端处理请求
  • 服务端返回响应结果
  • 关闭 TCP 连接
  • 浏览器解析 HTML 并渲染布局

DNS 域名解析

我们访问一个网站的时候,可以通过主机名或者域名来访问。但是绝大多数的时候是使用域名来访问网站。因为相对于主机名的 ip 地址,域名更能让人记住。

但是 TCP/IP 协议是通过 IP 地址来访问的,所以就需要一个机制,将域名转换为 IP 地址

而 DNS 服务就是做这件事情,它提供了域名到 IP 地址之间的解析服务

当客户端收到你输入的域名地址后,它首先去找本地的 hosts 文件,检查在该文件中是否有相应的域名、IP 对应关系,如果有,则向其 IP 地址发送请求,如果没有,再去找 DNS 服务器。一般用户很少去编辑修改 hosts 文件。

DNS 服务器层次结构

DNS 服务器迭代查询和递归查询

DNS 解析过程

浏览器客户端向本地 DNS 服务器发送一个含有域名 www.mybj123.com 的 DNS 查询报文。

本地 DNS 服务器把查询报文转发到根 DNS 服务器,根 DNS 服务器注意到其 com 后缀,于是向本地 DNS 服务器返回 comDNS 服务器的 IP 地址。

本地 DNS 服务器再次向 comDNS 服务器发送查询请求,comDNS 服务器注意到其 www.mybj123.com 后缀并用负责该域名的权威 DNS 服务器的 IP 地址作为回应。

最后,本地 DNS 服务器将含有 www.mybj123.com 的 IP 地址的响应报文发送给客户端。

从客户端到本地服务器属于递归查询,而 DNS 服务器之间的交互属于迭代查询。

正常情况下,本地 DNS 服务器的缓存中已有 comDNS 服务器的地址,因此请求根域名服务器这一步不是必需的。

DNS 的优先级

本地电脑会将一些经常使用的域名和对应的 IP 地址建立一个映射关系,并保存到本地 host 文件中。当 DNS 解析的时候,会优先从本地 host 文件中查找映射的 IP 地址映射

  1. 如果在本地host文件中找到了域名对应的IP地址映射,会直接使用 host 文件中的 IP 地址
  2. 如果在本地 host 文件中没有找到域名对应的 IP 地址映射,会从本地 DNS 服务器中查找
  3. 如果在本地 DNS 服务器中也没有找到域名对应的IP地址映射,会继续向上一级的 DNS 服务器发送请求,直到DNS 根服务器。如果找到,就进行回传,返回给浏览器。

建立 TCP 链接

先了解一个知识点:TCP/IP 协议族

TCP/IP 协议族是由四层协议组成的系统。分别是:

  • 应用层(http)
  • 传输层(tcp)
  • 网络层(ip)
  • 链路层(网络硬件)

建立 TCP 链接

我的理解是:我们访问一个网站之前,首先要保证有网络对吧?有网线/路由器对吧?那么此时,链路层就是 ok 的。经过上面第一步,已经知道了该域名映射的 IP 地址,并且可以访问,那么此时网络层也是 ok 的

那么接下来,就是传输层,也就是 TCP。其实这里说的也不是很严谨,传输层不仅仅是TCP一种协议,还有UDP 协议。UDP 协议是无连接的,因为其不需要连接,所以效率比较高,但是也是因为不需要连接验证所以安全性和可靠性得不到保障。而TCP 是面向连接的,有校验机制。所以用的较广泛。但是也有缺点:因为提前建立了连接,所以效率就较低。本文说的传输层指的是TCP 协议

为了确保连接双方的可靠性,在双方建立连接时,TCP 采用了三次握手策略

三次握手策略

上图理解为:

客户端发送一个带有 SYN 标志的数据包给服务端,服务端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息,最后客户端再回传一个带 ACK 标志的数据包,代表握手结束,连接成功。

上图也可以这么理解:

客户端:“你好,在家不,有你快递。”

服务端:“在的,送来就行。”

客户端:“好嘞。”

知其然更要知其所以然,为什么要进行三次握手才能建立 TCP 连接?

根本原因就是为了确保客户端和服务端双方的接收和发送能力都是 ok 的

经过第一次握手后,服务端收到了客户端的SYN请求标志,那么此时服务端就可以知道:客户端的发送能力是 ok 的,服务端本身自己的接收能力是 ok 的

经过第二次握手后,客户端收到了服务端的SYN+ACK请求+返回标志,那么此时,客户端就可以知道:客户端本身的发送和接收能力是 ok 的,服务端的发送和接收能力有是 ok 的

经过第三次握手后,服务端接收到了客户端的ACK返回标志,那么此时,服务端就可以知道:服务端本身自己的接收和发送能力是 ok 的

发送 HTTP 请求

建立TCP连接之后,就可以发送 HTTP 请求了。说到HTTP请求,那么前端同学就不得不了解下关于 HTTP 报文的相关知识点。

发送 HTTP 请求

这样看不怎么直观,我们可以通过 curl(命令行网络测试工具)来测试发起请求的报文结构。这里我们以百度为例。

打开终端,输入curl -v www.baidu.com,可以看到:

发送 HTTP 请求

上方截图的请求报文旁边空白比较少,单独拎出来讲一下:

GET / HTTP/1.1 // 请求行 (方法/路径/协议)

// 以下是请求头
Host: www.baidu.com
User-Agent:curl/7.54.0
Accept: */*
// 空行

// 请求体 因为没有任何参数 所以是空的

这里我整理一些常用的报文头。

请求头和响应头都属于报文头

常用报文头

  1. Accept: 客户端可以接受的媒体类型
    Accept:text/html: 表示浏览器可以接受服务器返回的类型是tetx/html。也就是常说的 html 文档 但是如果服务器无法返回 text/html 类型的数据,服务器应该返回一个406(Non Acceptable)错误
    Accept:*\*: 代表浏览器可以处理所有类型
    – 如果想要给显示的媒体类型增加优先级 则可以使用q=?来额外表示权重。权重 q 的范围是 0~1, 权重 q 默认是 1
  2. Accept-Encoding: 浏览器申明自己的编码方法
    – 通常指定压缩方法 是否支持压缩 支持什么压缩方法(gzip / deflate)
  3. Accept-Language: 浏览器申明自己的语言
    Accept-Language:zh-cn,zh;q=0.7,en-us,en;q=0.3
    – 也可以指明权重信息
  4. Connection:keep-alive
    – 当一个网页打开完成后,客户端和服务端之间用于传输 HTTP 数据的 TCP 连接不会关闭,注意是 TCP 连接。这样做的好处是 避免多次的 3 次握手和 4 次挥手
    Connection:close
    – 当一个网页打开完成后,客户端和服务端之间用于传输 HTTP 数据的 TCP 连接会关闭
    – 当客户端再次发送请求时,需要重新建立 TCP 连接
  5. Host: 被请求资源的 Interent 主机名和端口号
    – 它通常从 URL 中提取出来
    – www.xxx.com:8080
  6. Referer: 来源
    – 用于告知服务器是从哪个链接进来的,服务器借此可以获得一些信息用于处理
  7. User-Agent: 告诉服务器 客户端使用的操作系统的名称和版本
    – 服务端可以通过User-Agent来判断浏览器类型,作出不同的兼容处理
  8. Content-Type: 说明报文体内对象的媒体类型
    text/html:HTML 格式
    text/plain:纯文本格式
    text/xml:XML 格式
    image/gif:gif 图片格式
    text/jpeg:jpg 图片格式
    text/png:png 图片格式
    application/json:JSON 数据格式
    application/xxml:XML 数据格式
    application/msword:Word 文档格式
    application/octet-stream:二进制数据流(常见于文件下载)
    application/x-www-form-urlencoded:表单提交

服务器处理请求

服务器端收到请求后的由 web 服务器(准确说应该是 http 服务器)处理请求,诸如 Apache、Ngnix、IIS 等。web 服务器解析用户请求,知道了需要调度哪些资源文件,再通过相应的这些资源文件处理用户请求和参数,并调用数据库信息,最后将结果通过 web 服务器返回给浏览器客户端。

服务器处理请求

返回响应结果

在 HTTP 里,有请求就会有响应,哪怕是错误信息。这里我们同样看下响应报文的组成结构:

返回响应结果

在响应结果中都会有个一个 HTTP 状态码,比如我们熟知的 200、301、404、500 等。通过这个状态码我们可以知道服务器端的处理是否正常,并能了解具体的错误。

状态码由 3 位数字和原因短语组成。根据首位数字,状态码可以分为五类:

  • 1xx: 指示信息 – 表示请求已接受,但是需要继续处理 临时响应
  • 2xx: 成功 – 表示请求已被成功接收
  • 3xx: 重定向 – 要完成请求必须进行更进一步的操作
  • 4xx: 客户端错误 – 请求有语法错误或请求无法实现
  • 5xx: 服务器错误 – 服务器未能实现合法的请求

常用状态码

  • 200 OK:客户端请求成功
  • 202 Accepted: 已接受 已经接受请求 但是未处理完成
  • 206 Partial Content断点续传 客户发送了一个带有 Range<范围>头的 GET 请求,服务器完成了 它 <请求视频或者音频文件很大的时候 服务器就会给你返回部分[Range] 的文件>
  • 301 Moved Permanently:所请求的页面已经转移至新的 url <永久重定向>
  • 302 Found:所请求的页面已经临时转移至新的 url <临时重定向>
  • 304 Not Modified之前缓存可用 客户端有缓存的文档并发出了一个条件性的请求,服务器告诉客户端,原来缓存的文档还可以继续使用
  • 400 Bad Request:客户端请求语法错误,不能被服务器所理解
  • 401 Unauthorized:请求未经授权 要求用户的身份认证,这个状态码必须和 WWW-Authenticate 报头域一起使用
  • 403 Forbidden: 服务器理解请求客户端的请求,但是拒绝执行此请求
  • 404 Not Found请求资源不存在
  • 500 Internal Server Error:服务器内部错误,无法完成请求
  • 502 Bad Gateway网关或代理的服务器发生了错误 从远端服务器接收到了一个无效的请求
  • 503 Server Unavailable请求未完成,服务器临时过载或宕机,一段时间后可能恢复正常

关闭 TCP 连接

为了避免服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方都可以发起关闭请求。与创建 TCP 连接的 3 次握手类似,关闭 TCP 连接,需要4 次握手

4 次握手

TCP 四次挥手断开连接

经过之前的三次握手客户端和服务端都进入了ESTAB-LISHED状态

  1. 第一次挥手客户端发送带有FIN 标志的断开连接请求报文段,然后客户端就进入了FIN-WAIT-1 状态(终止等待状态 1)等待服务器确认
  2. 第二次挥手服务端接收到了客户端浏览器发送的FIN 标志报文段后,需要发送ACK 确认报文段对这个FIN 报文段进行确认,此时服务端进入CLOSE-WAIT 状态(关闭等待状态)。客户端收到该 ACK 却报文段后,客户端就进入了FIN-WAIT-2 状态(终止等待状态 2)。(此时客户端向服务端的 TCP 连接已经关闭。但是服务端向客户端的 TCP 连接还没有关闭)
  3. 第三次挥手等待服务端已经没有任何数据发送给客户端之后,服务端会向客户端发送FIN+ACK 报文段(关闭+确认)。然后服务端进入到LAST-ACK 状态(最后确认状态)
  4. 第四次挥手客户端向服务端发送ACK 确认标志。服务端收到该确认信息后进入到CLOSED 状态(TCP 关闭状态)。客户端在等待2MSL(报文最大生存时间)时间后,也进入到了CLOSED 状态(TCP 关闭状态)。此时四次挥手成功,客户端和服务端双方都已关闭 TCP 连接

上图如果实在理解不了大家也可以这么理解:

客户端:“兄弟,我这边没数据要传了,咱关闭连接吧。”

服务端:“收到,我看看我这边有木有数据了。”

服务端:“兄弟,我这边也没数据要传你了,咱可以关闭连接了。”

客户端:“好嘞。”

面试中关于四次挥手经常问到的是:为什么最后客户端会等待一段时间之后才会进入关闭状态?

因为最后一次挥手客户端发送给服务端的确认信息,服务端可能会没有收到。那么如果服务端没有收到客户端发送的最后确认信息,那么服务端会认为我本身发送给客户端的关闭请求因为客户端没有收到该请求,所以客户端才没有给我发送确认信息,我才会收不到。所以服务端会再次向客户端发送该关闭请求。为了避免客户端真的没有收到服务端的关闭请求,客户端会等待一段时间(报文最大生存时间)之后,再进入关闭状态

浏览器解析 HTML 并渲染布局

客户端浏览器在收到服务端的响应结果后,就要开始解析并渲染了,

webkit 引擎渲染大致过程:

webkit 引擎渲染大致过程

  1. HTML 经过 HTML Parser 转成 DOM Tree(DOM 树)
  2. CSS 按照 CSS 规则和 CSS Parser 转成 CSS Tree
  3. DOM TreeCSS Tree 结合形成 Render Tree
  4. 通过Layout精确的计算出要显示的DOM真正的位置
  5. 浏览器通过Paint显示出最终的页面效果

这其中有几个经常会被问到的面试题

什么是重绘(Repaint)?

重绘就是Repaint,是在一个元素的外观被改变,但没有改变布局(改变元素的非几何属性)的情况下发生的,如改变了visibilityoutlinebackground等。当 repaint 发生时,浏览器会验证 DOM 树上所有其他节点的visibility属性。

当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来以后,浏览器便把这些元素都按照各种的特性绘制一遍,于是页面的内容就出现了,这个过程称之为 repaint

如何触发重绘(Repaint)?

改变元素非几何属性(外观属性)。如:color background-color 等

什么是重排(Reflow)?

DOM 结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式来计算并根据计算结果将元素放到它该显示的位置(改变元素的几何属性),这个过程称之为reflow

如何触发重排(Reflow)?

  1. 增加、删除、修改 DOM 节点时 会导致 Reflow 或 Repaint
  2. 移动 DOM 的位置 或者 DOM 动画的时候
  3. 修改 CSS 样式的时候
  4. Resize 窗口大小的时候(移动端没有这个问题),或是滚动的时候 都有可能触发Reflow
  5. 修改网页的默认字体的时候

减少 Reflow 对性能的影响的建议?

Reflow(回流)是导致 DOM 脚本执行效率低的关键因素之一,页面上任何一个节点触发了 Reflow,会导致它的子节点及祖先节点的重新渲染

  1. 不要一条一条地修改 DOM 的样式,预先定义好 class,然后修改 DOMclassName
  2. 把 DOM 离线后再修改,比如:先把 DOMdisplay:none (有一次 Reflow),然后修改 100 次后,然后再把它 display:block
  3. 不要把 DOM 节点的属性值放在一个循环里当成循环里的变量
  4. 尽可能不修改影响范围比较大的 DOM
  5. 为动画的元素使用定位 absolute / fixed
  6. 慎重选择高消耗的样式,比如有: box-shadows | border-radius | transparency | transforms |CSS filters(性能杀手)
  7. 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局

重排和重绘的关系?

重排必定会引发重绘,但重绘不一定会引发重排

结语

以上就是今天码云笔记为大家整理的关于前端浏览器输入 URL 后发生什么的个人学习笔记,文章有点长,但是干货满满,这个也是前端面试常问的经典面试题,作为一个前端开发是必知的知识。可能有些整理的不全,但是后期还会更新,也欢迎大家拍砖。

「点点赞赏,手留余香」

1

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 前端浏览器输入URL后发生什么?个人笔记

发表回复