从输入URL到出现页面的一系列事件总结

177 阅读12分钟

这篇是综合了好几篇帖子写的(侵删!!),我觉得可以延伸出来问的知识点。第一次写面经总结,大家多多指教!

  • DNS解析
  • 发起TCP连接
  • 发送HTTP请求
  • 服务器处理请求并返回HTTP报文
  • 浏览器解析渲染页面
  • 连接结束。

DNS解析

DNS解析实际上就是寻找你所需的资源的过程。整个过程就和我们⽇常⽣活中找⼈问路的过程类似,只指路不带路。

以域名的层级关系类似⼀个树状结构:

  • 根 DNS 服务器
  • 顶级域 DNS 服务器(com)
  • 权威 DNS 服务器(server.com)
  1. 客户端发出一个DNS请求,问 www.server.com的IP,发送给本地DNS服务器;
  2. 本地DNS服务器收到客户端的请求后,如果能在缓存中找到 www.server.com,则直接返回IP地址。否则则发送请求询问根DNS服务器 www.server.com的IP地址;
  3. 根DNS服务器收到请求后,发现后置是.com,于是讲顶级域DNS服务器的地址返回给本地DNS服务器;
  4. 本地DNS服务器发送请求询问顶级域DNS服务器 www.server.com的IP地址;
  5. 顶级域DNS服务器返回权威DNS服务器地址给本地DNS服务器;
  6. 本地DNS服务器发送请求询问权威DNS服务器 www.server.com的IP地址;
  7. 权威DNS服务器查询后将相应的IP地址返回给本地DNS服务器;
  8. 本地DNS服务器将IP地址返回给客户端,客户端与目标建立链接。

发起TCP连接

三次握手

image.png 第三次握⼿是可以携带数据的,前两次握⼿是不可以携带数据的

为什么是三次握手,不是两次或者四次?

TCP链接:用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括Socket、序列号和窗口大小称为链接。

三次握手才能初始化Socket、序列号和窗口大小并建立TCP链接。

从三个方面分析三次握手的原因:

  • 三次握手才可以阻止重复历史连接的初始化(主要原因)

    客户端发生多次SYN建立请求的报文,在网络拥堵的情况下:

    • 一个【旧SYN报文】比【最新的SYN】先到达服务端;
    • 此时服务端就会回一个【SYN+ACK】报文给客户端;
    • 客户端收到可根据自身上下文判断这是一个历史链接(序列号过期或超时),那么客户端就会发送RST报文终止这一次链接。
  • 三次握手才可以同步双方的初始化序号

    TCP协议的双方都必须维护【序列号】,它的作用:

    • 接收方可以去除重复的数据;
    • 接收方可以根据数据包的序列号按序接收;
    • 可以标识发送出去的数据包中,哪些是已经被对方接收的;

    三次握手的一来一回可以确保双方的初识序列号被可靠的同步。

    四次握手也可以,但是步骤多余了,三次握手就足够。

    两次握手只保证了一方的初识序列号被对方成功接收。

  • 三次握手才可以避免资源浪费

    如果只有两次握手,客户端的SYN在网络请求中堵塞,客户端没有收到ACK报文,就会重新发送SYN报文。由于没有第三次握手,服务端不清楚客户端是否收到了自己发送的ACK确认报文,所以只能每收到一个SYN报文便建立一个链接,造成了资源浪费。

四次挥手

image.png

为什么挥手需要四次?

四次挥手时双方发送FIN的过程:

  • 关闭连接时,客户端向服务端发送FIN报文仅仅表示客户端不再发送数据了但是还能接收数据。
  • 服务端收到了客户端的FIN报文后,先回复一个ACK应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送FIN报文给客户端同意关闭连接。

所以为了服务端完成数据的发送和处理,ACK和FIN是分开发送的,所以需要四次挥手。

为什么客户端最后还要等待2MSL/为什么需要 TIME_WAIT 状态?

  • 保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
  • 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

发送HTTP请求

发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议发送到服务器指定端口。请求报文由请求行,请求头,请求正文组成。

请求行

请求行的格式为Method Request-URL HTTP-Version CRLF eg: GET index.html HTTP/1.1 常用的方法有: GET,POST, PUT, DELETE, OPTIONS, HEAD

GET和POST的区别

  • 缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
  • 编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
  • 参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
  • 幂等性的角度,GET 是幂等的,而 POST 不是。(幂等表示执行相同的操作,结果也是相同的)
  • TCP 的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

请求头

请求头中使用了Accept,Accept-Encoding,Accept-Language,Cache-Control,Connection,Cookie等字段。

  • Accept用于指定客户端用于接受哪些类型的信息;
  • Accept-Encoding用于指定接受的编码方式;
  • Connection设定为Keep-alive用于告诉客户端本次HTTP请求结束后并不需要关闭TCP连接,这样下次HTTP请求可以使用相同的TCP管道,节省时间。

请求正文

请求通常需要客户端向服务端传输数据。这些数据就储存在请求正文中。在请求头中会有一些与请求正文相关的信息,例如Content-Type: application/json,表示请求的数据格式为json。

HTTP缓存

缓存规则分为强制缓存协商缓存

强制缓存

当缓存数据库中有客户端所需的数据,客户端直接从中拿出来使用,当缓存服务器没有需要的数据时,客户端才会向服务端请求。

图片 1.png

Cache-Control:

  • 在Responde Headers中。
  • 控制强制缓存的逻辑。
  • 例如 Cache-Control: max-age=3153600(单位是秒)

Cache-Control的值:

  • max-age:缓存最大过期时间。
  • no-cache:可以在客户端存储资源,每次都要去服务端做新鲜度校验,来决定是从服务端获取新的资源(200)还是使用客户端缓存(304)。
  • no-store:永远不要在客户端存储资源,永远去原始服务器获取资源。

协商缓存

客户端会先从缓存数据库拿到一个缓存的标识,然后向服务端检验标识是否失效,入门没有失效服务端返回304,这样客户端可以去缓存数据库拿出数据。如果失效,服务端会返回新的数据。

图片 2.png

资源标识:

  • 在Responde Headers中,有两种。
  • Last-Modified:资源最后修改的时间。
  • Etag:资源的唯一标识,一个字符串。
Last-Modified

图片 3.png

服务端拿到 if-Modified-Since 之后拿这个时间去和服务端资源最后修改时间做比较,如果一致则返回 304 ,不一致(也就是资源已经更新了)就返回 200 和新的资源及新的 Last-Modified。

Etag

图片 4.png

其实 Etag 和 Last-Modified 一样的,只不过 Etag 是服务端对资源按照一定方式(比如 contenthash)计算出来的唯一标识,就像人类指纹一样,传给客户端之后,客户端再传过来时候,服务端会将其与现在的资源计算出来的唯一标识做比较,一致则返回 304,不一致就返回 200 和新的资源及新的 Etag。

两者比较
  • 优先使用 Etag。
  • Last-Modified 只能精确到秒级。
  • 如果资源被重复生成,而内容不变,则 Etag 更精确。

综述

图片 5.png

三种刷新操作对 http 缓存的影响

  • 正常操作:地址栏输入 url,跳转链接,前进后退等。
  • 手动刷新:f5,点击刷新按钮,右键菜单刷新。
  • 强制刷新:ctrl + f5,shift+command+r。

正常操作:强制缓存有效,协商缓存有效。 手动刷新:强制缓存失效,协商缓存有效。 强制刷新:强制缓存失效,协商缓存失效。

服务器处理请求并返回HTTP报文

它会对TCP进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用。这一部分工作由web服务器进行,如Tomcat、Nginx、Apache等。HTTP报文也分为三部分,状态码、响应头和响应报文。

状态码

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

200 成功

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

301 永久移动

请求的网页已永久移动到新位置。服务器返回此响应时,会自动将请求者转到新位置。

302 临时移动

服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

304 未修改

自从上次请求后,强求的网页未修改过。服务器返回此响应时,不会返回网页内容。

400 错误请求

服务器不理解请求的语法。

401 未授权

请求要求身份验证。对于需要登录的网页,服务器可能会响应。

403 禁止

服务器拒绝请求。

404 未找到

服务器找不到请求的网页。

422 无法处理

请求格式正确,但是由于含有语义错误,无法响应。

500 服务器内部错误

服务器遇到错误,无法完成请求。

504 网关超时

未找到网关。

响应报头

常见的响应报头字段有: Server, Connection...。

响应报文

你从服务器请求的HTML,CSS,JS文件就放在这里面

浏览器解析渲染页面

webkit渲染过程

浏览器渲染过程如下:

  1. 解析HTML,生成DOM树,解析CSS,生成CSSOM树;
  2. 将DOM树和CSSOM树结合,生成渲染树(Render Tree)只包含可见的节点;
  3. Layout(回流):根据生成的渲染树,进行回流,得到节点的几何信息(位置,大小);
  4. Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素;
  5. Display:将像素发给GPU,展示在页面上。

回流:无论通过什么方式影响了元素的几何信息(元素在视口内的位置和尺寸大小),浏览器需要重新计算元素在视口内的几何属性,这个过程叫做回流。

重绘:通过构造渲染树和重排(回流)阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(元素在视口内的位置和尺寸大小),接下来就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘。

何时发生回流重绘

页面布局和几何信息发生变化的时候,就需要回流。如:

  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化
  • 内容发生变化
  • 页面一开始渲染的时候
  • 浏览器的窗口尺寸变化

注意:回流一定会触发重绘,而重绘不一定会回流。

如何减少回流和重绘

  • 最小化回流和重排,比如样式集中改变,使用添加新样式类名 .classcssText
  • 批量操作 DOM,比如读取某元素 offsetWidth 属性存到一个临时变量,再去使用,而不是频繁使用这个计算属性;又比如利用 document.createDocumentFragment() 来添加要被添加的节点,处理完之后再插入到实际 DOM 中。
  • 使用absolute或 fixed 使元素脱离文档流,这在制作复杂的动画时对性能的影响比较明显。
  • 开启 GPU 加速,利用 css 属性 transformwill-change 等,比如改变元素位置,我们使用 translate 会比使用绝对定位改变其 lefttop 等来的高效,因为它不会触发重排或重绘,transform 使浏览器为元素创建⼀个 GPU 图层,这使得动画元素在一个独立的层中进行渲染。当元素的内容没有发生改变,就没有必要进行重绘。