浏览器输入url到页面渲染的流程与HTTP协议

浏览器输入url到页面渲染的过程 看完你就懂了

浏览器输入url后发生了什么
当你在浏览器中想访问www.google.com时,会进行以下操作

首先查看浏览器中是否有缓存,如果有则继续查看缓存是否过期,如果没有过期,直接返回缓存页面,如果没有缓存或者缓存过期,发送一个请求。

浏览器发送请求后发生了什么

应用层

  • DNS解析,这里 DNS服务器通过域名查询到具体的IP然后下发数据给传输层
    这个查询是由操作系统来进行的。
    1.首先在本地缓存中查询 IP (没有就往下走)
    2.去系统配置的 DNS 服务器中查询(没有就往下走)
    3.去 DNS 根服务器查询,找出负责com这个一级域名的服务器,然后去该服务器查询google这个二级域名
    4.接下来如果有三级域名,那么三级域名的查询其实是我们配置的,你可以给三级域名配置一个 IP。
    以上是 DNS的迭代查询,是由客户端去做请求的。
    说到缓存,这里顺便提一下HTTP缓存策略(有兴趣可以看这部分的内容)。
    HTTP缓存策略

HTTP是什么?

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是一种网络传输协议,它使得浏览器和服务器之间可以进行信息、资源的传输(文字、图片、二进制、音频、视频等)。所有的WWW文件都必须遵守这个标准.

缓存策略

http根据是否要向服务器发送请求将缓存规则分为了两类:强缓存和对比缓存(对比缓存也叫做协商缓存)。

  • 强缓存

直接从缓存数据库中取出资源,无需再发送请求到服务器上。在这里不得不提的两个响应头字段是Cache-Control和Expires。
浏览器输入url到页面渲染的流程与HTTP协议
1.在浏览器第一次访问某个服务器时,本地还没有资源副本被缓存,于是会发送一个请求到服务器中请求资源。
2.服务器响应资源时会在响应头里带上Cache-Control和Expires字段来告诉浏览器这个资源是否允许缓存,如果允许的话这个资源的过期时间是多久。
3.在有效期内如果再次请求同样的资源,浏览器就不会再发送请求到服务器请求了,而是直接到本地缓存中取。
所以很多时候我们看到响应的状态码为200时后面还会带上注释from disk(or memory) cache。
总所周知,从内存中取数据的速度会比从硬盘中取快,所以通常的缓存策略是在我们打开一个最近访问过的网站的时候,看到的是from disk cache,但是当再次刷新页面的时候就会变成from memory cache。因为浏览器(或页面标签)关闭后内存中的缓存就会被释放,重新打开页面取不到该缓存。

  • 对比缓存

需要经过服务器确认是否使用缓存的机制,其http状态码为304,意为not modified,表示可以从缓存中取资源。如果返回的是状态码是200,则同时服务器会把最新资源的完整内容返回给浏览器。在这里不得不提的两组头字段是Last-Modified/If-Modified-Since 和 ETag/If-None-Match。
浏览器输入url到页面渲染的流程与HTTP协议1.在浏览器第一次请求资源时,服务器会在响应头里带上Last-Modified字段来告诉浏览器这个资源最后一次更新的时间。
2.在浏览器第二次想要访问这个资源时,会将上次服务器响应的Last-Modified的值存放到If-Modified-Since里发送给服务器。
3.服务器会将这个时间与资源最新修改日期进行比较。如果一致,返回304表示缓存可用,服务器就不再返回内容给浏览器了,同时Last-Modified头也不会返回,因为资源没被修改。如果不一致就返回200和Last-Modified头并且返回最新的资源。
不难理解,Last-Modified /If-Modified-Since这组头信息是基于资源的修改时间来判断资源有没有更新的。Etag/If-None-Match的流程是一样的,区别在于这组头信息是基于资源的内容的摘要信息(比如MD5 hash)来判断资源有没有更新。用ETag的好处是如果因为某种原因资源修改了但是时间没改变,那么用ETag就能区分资源是不是有被更新。如果同时存在两组头信息,ETag的优先级会高于Last-Modified。
浏览器输入url到页面渲染的流程与HTTP协议

传输层

  • 通过TCP三次握手和服务器建立连接,四次挥手释放连接,这里 TCP 协议会指明两端的端口号
    TCP 协议的作用是,提供可靠的字节流服务,保证数据通信的完整性和可靠性,防止丢包。字节流服务是指,为了方便传输,将大块数据分割成以报文段为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠地传给对方。
    TCP协议为了更容易传送大数据才把数据分割,而且TCP协议能够确认数据最终是否送达到对方。
  • TCP握手结束后会进行TLS握手
    数据在进入服务端之前,可能还会先经过负责负载均衡的服务器,它的作用就是将请求合理的分发到多台服务器上,这时假设服务端会响应一个 HTML 文件。
    首先浏览器会判断状态码是什么,如果是 200 那就继续解析,如果 400 或 500 的话就会报错,如果 300 的话会进行重定向,这里会有个重定向计数器,避免过多次的重定向,超过次数也会报错。
  • 然后开始正式的数据传输,把数据下发到网络层。

网络层

  • IP协议会确定IP地址并指示在数据传输中如何转跳路由器,IP数据包会再被封装到数据链路层的数据帧结构中

数据链路层

  • 这是TCP/IP软件的最底层,负责接收IP数据包并通过网络发送,或者从网络上接受物理帧,抽出IP数据包,交给IP层。

浏览器输入url到页面渲染的流程与HTTP协议

浏览器解析文件到渲染的过程

前面提到在服务端响应回一个文件后首先浏览器会判断状态码是什么,如果是 200 那就继续解析,如果 400 或 500 的话就会报错,如果 300 的话会进行重定向,这里会有个重定向计数器,避免过多次的重定向,超过次数也会报错。

  • 当浏览器开始解析文件时
    如果是 gzip 格式的话会先解压一下,然后通过文件的编码格式知道该如何去解码文件。
  • 构建 DOM 树、构建 CSSOM 树、解析JS
    文件解码成功后会正式开始渲染流程,先会根据 HTML 构建 DOM 树,有 CSS 的话会去构建 CSSOM 树。如果遇到 script 标签的话,会判断是否存在 async 或者 defer ,前者会并行进行下载并执行 JS,后者会先下载文件,然后等待 HTML 解析完成后顺序执行。
    如果以上都没有,就会阻塞住渲染流程直到 JS 执行完毕。遇到文件下载的会去下载文件,这里如果使用 HTTP/2 协议的话会极大的提高多图的下载效率。
  • 生成 Render 树
    CSSOM 树和 DOM 树构建完成后会开始生成 Render 树,这一步就是确定页面元素的布局、样式等等诸多方面的东西
  • 调用 GPU 绘制,合成图层,将内容显示在屏幕上了
    在生成 Render 树的过程中,浏览器就开始调用 GPU 绘制,合成图层,将内容显示在屏幕上了。

拓展:队头阻塞

通过上面的介绍,我们知道了在每次发送请求的时候都要在传输层通过TCP三次握手和服务器建立连接,四次挥手释放连接。
在HTTP0.9之前,每次请求都要经历这个过程,导致浪费很多资源和时间。针对这个问题,在HTTP1.0里增加了Connection: Keep-Alive字段。在HTTP1.1里引入了持久连接和管道机制。

Connection: Keep-Alive

保持TCP通道的连接状态,降低了建立TCP通道的性能消耗。keep-alive并不是默认使用的。客户端必需发送一个Connection:Keep-Alive 请求首部来**keep-alive连接。 如果服务器愿意为下一条请求将连接保持在打开状态,就在响应中包含相同的首部,如果响应中没有Connection:Keep-Alive 首部,客户端就认为服务器不支持keep-live,会在发回响应报文后关闭连接。

持久连接

HTTP/1.1逐渐停止了对keep-alive连接的支持,用一种名为持久连接的改进型设计取代了它。持久连接的目的与keep-alive连接的目的相同,但是工作机制更优些。HTTP/1.1持久连接在默认情况下是**的,除非特别指明。要在事务处理结束之后将连接关闭,HTTP/1.1应用程序必须向报文中显示地添加一个Connection:close首部。
但是,不发送Connection:close并不意味这服务器承诺永远将连接保持在打开状态,客户端和服务器仍然可以随时关闭空闲的连接。

管道化连接(pipeLining)

HTTP1.1 允许在持久连接上可选择使用管道化连接。在等待上一个请求响应的同时,发送下一个请求(pipeLining其实是把多个Http请求放到一个TCP连接中一一发送,在发送过程中不需要等待服务器对前一个请求的响应;只不过,服务器还是要按照发送请求的顺序处理请求,客户端还是要按照发送请求的顺序来接收响应)。
浏览器输入url到页面渲染的流程与HTTP协议

所以,队头阻塞到底是什么?这些和队头阻塞又有什么关系呢?

前面提到HTTP管道化要求服务端必须按照请求发送的顺序返回响应,那如果一个响应返回延迟了,那么其后续的响应都会被延迟,直到队头的响应送达。

有没有解决队头阻塞的方法?

HTTP/2 协议的多路复用(复用TCP连接)
HTTP2引入了帧、消息和数据流等概念,每个请求/响应被称为消息,每个消息都被拆分成若干个帧进行传输,每个帧都分配一个序号。具有相同四元组(源地址,源端口,目的地址,目的端口)的帧在传输时都属于一个数据流,即一条流有很多个帧,而一个连接上可以存在多个数据流,各个帧在流和连接上独立传输,到达之后再组装成消息,这样就避免了请求/响应阻塞。
当然,即使使用HTTP2,如果HTTP2底层使用的是TCP协议,仍可能出现TCP队头阻塞。
并发连接
我们知道对于一个域名而言,是允许分配多个长连接的,那么可以理解成增加了任务队列,也就是说不会导致一个任务阻塞了该任务队列的其他任务,在RFC规范中规定客户端最多并发2个连接,不过实际情况就是要比这个还要多,举个例子,Chrome中是6个。
域名分片
顾名思义,我们可以在一个域名下分出多个二级域名出来,而它们最终指向的还是同一个服务器,这样子的话就可以并发处理的任务队列更多,也更好的解决了队头阻塞的问题。

拓展:HTTP/2

最后总结一下HTTP/2的几个新特性

  • 二进制分帧(Binary Framing)
  • 多路复用(Request and Response Multiplexing)
  • 流优先级( Stream priority)
  • 服务器推送(Server push)
  • 头部压缩(Header Compression)
  • 具体了解请移步https://www.cnblogs.com/yingsmirk/p/5248506.html