「彻底吃透篇」从输入 URL 地址到看到页面中间经历的环节

纯干货分享「必看」

从输入 URL 到找到服务器拿数据,整个环节的大体流程:

  • URL 解析:首先要到 DNS 服务器上进行 DNS 域名解析「DNS 域名解析服务器上会增加一条记录」拿到域名和外网 IP
  • 通过外网 IP 找到服务器,通过 DNS 解析出来的 URL 参数,找到资源,最后返回给客户端,进行渲染

1. URL 解析

EG:http://user:pass@www.guyal.cn:80/index.html?lx=1&from=wx#video

传输协议:用于客户端和服务器端间的数据传输

  • HTTP 超文本传输协议「除了可以传输文件,还可以传输除文本之外的资源:音视频…」
  • HTTPS 在 HTTP 的基础上进行了安全设置「需要申请证书认证:SSL/TSL,每次数据传输都需要进行一个安全校验,符合条件之后,才会进行建立连接」
  • FTP 一般用于当前开发者电脑和服务器端之间的文件传输「把写好的代码利用 FTP 传到服务器上,同一局域网下,可以实现资源的分享」

HTTP/HTTPS/FTP…
登录信息「认证」
user:pass
域名/服务器地址,域名分为:顶级域名、一级域名、二级域名…

  • 顶级域名:解析的时候可以增加多个解析记录
  • 二级域名一般都是配不同的服务器,不会配置不同的端口「这样就不会每次输入耳机域名都要输出端口号」

www.guyal.cn
端口号:0-65535 之间

  • 自己写地址的时候,不加端口号,浏览器或按照默认端口号自动补上「但是发给服务器的一定带着端口号」
  • 端口号就是用来区分同一台服务器上的不同项目的「Nginx 配置的时候设置」
80:HTTP 默认端口号
443:HTTPS 默认端口号
21:ftp 默认端口号

请求资源的文件路径

index.html

查询字符串:问号参数

lx=1&from=wx

问号传参也会涉及到 URL 编码问题,简单说一下:

URL 编码

对于一些特殊的字符,我们在客户端和服务器端传递的时候,需要进行编码和解码

编码/解码的方法

  • encodeURI(url)/decodeURI:主要是对地址中的空格或者中文汉字等进行编码「处理的是整个 URL」
  • encodeURIComponent/decodeURLComponent:在 encodeURI 基础上,对地址中的冒号(:)或者是斜杠(/)等也会进行编码「编译特殊符号,用于传递参数的编译」
  • escape/unescape:特殊符号和中文也都可以编译,但是不是所有的后台语言都支持这个方法,所以一般只用于客户端不同页面之间的数据传输,信息的编码解码「例如:自己存储的 cookie/localstorage」
http://user:pass@www.guyal.cn:80/index.html?lx=1&from=${encodeURIComponent('http://www.baidu.com/')}#video

片段标识符:HASH 值

  • 锚点定位
  • HASH 路由

video

2. 缓存检查

缓存

  • 在客户端不需要做任何的事情,浏览器会帮我们处理好
  • 在服务器端也不是代码实现的,而是 web 服务器部署工具就有的

缓存的作用

URL 解析完成之后,会进行一个缓存检查,如果本地有缓存,则在本地缓存中拿数据资源,没有则会发送 HTTP 请求;

缓存的方案
强缓存:Expires「 HTTP1.0」/cache-Control「HTTP1.1」

  • 浏览器对于强缓存的处理:根据第一次请求资源时返回的响应头来确定的
  • Expires(ek- ɪk’sbaɪɚz):缓存过期时间,用来指定资源到期的时间
  • Cache-Control:cache-control: max-age=2592000第一次拿到资源后的2592000秒内(30天),再次发送请求,读取缓存中的信息(HTTP/1.1)
  • 两者同时存在的话,Cache-Control优先级高于Expires
    协商缓存:Last-Modified / ETag
  • 协商缓存是对强缓存的一种辅助:也就是说,强缓存生效的时候,使用强缓存;强缓存失效或者没有,才是需要看是否有协商缓存
  • 强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程
  • 协商缓存生效,返回 304 和 Not Modified
    数据缓存: localStorage 本地存储
  • 对于不经常更新的数据,通过使用 localStorage 存储方式,也可以实现强缓存或者协商缓存一样建立缓存机制
    • 方式:存储数据并存储当前时间,
    • 过程:当页面刷新的时候,首先检测本地是否有数据,以及存储的时间是否还在有效期内
      • 如果时间未过期,获取本地资源进行渲染
      • 如果时间过期或者本地没有数据,需要重新发送请求,获取的最新资源及修改时间重新存储到本地

不使用 cookie 的原因?

  • cookie 存储的信息太小了,一个源只有 4KB,而本地存储有 5MB

缓存的查找机制

  • 重新打开新的网页:查找硬盘中是否有匹配,如果有则使用,没有则发送网络请求
  • 普通刷新:F5「页面没有关闭」:先从内存中找有没有,没有则去硬盘中找,如果没有在去重新请求
  • 强制刷新:ctrl+F5:不管有没有缓存,全部从服务器来获取「不使用浏览器缓存」,所以请求头中均带有 Cache-control:no-cache「为了兼容,还带了 Pragma: no-cache」,服务器直接返回:200 和最新内容

根据浏览器的缓存机制,缓存的位置有两种情况

  • 内存缓存「Memory Cache」:临时缓存(页面未关闭)「存储在进程中的内存中(堆栈内存)」
  • 硬盘缓存「Disk Cache」:本地硬盘(页面关闭)

客户端缓存处理「强缓存和协商缓存」

强缓存

强缓存的字段说明

  • Expires「HTTP1.0」:一般存储的是时间,用来指定资源到期的时间日期(具体到哪一天过期)「expires: Thu, 13 Jun 2030 12:35:06 GMT」
    • 客户端时间是可以随意更改的
    • 服务器时间和客户端时间会存在时间差
  • Cache-Control「HTTP1.1」:max-age=2592000(存的是秒数),第一次拿到资源后的 2592000 秒内有效「30 天内有效:cache-control: max-age=2592000」
    • 基于时间,最小反应单位是秒
    • 如果在 1 秒内,客户端存储了信息,同时服务器更新了文件,这样检测不出来
    • 但是,基于标识是可以的「每一次更新标识是不一样的」
  • 两者都存在的话,Cache-Control 的优先级高级 Expires

浏览器强缓存的机制
第一次发起 HTTP 请求这个页面,首先查找浏览器缓存中是否有缓存

  • 若没有该请求的缓存结果和缓存标识「Expires/Cache-Control」,直接向服务器端发起 HTTP 请求
  • 服务器端返回该请求的结果和缓存规则「强缓存是由服务器设置的缓存规则」
  • 浏览器默认把请求结果和缓存规则及标识存储到浏览器缓存中
    当我们第二次请求该页面时,检测本地是否有缓存并且检查是否在有效期内「检查是否过期是自动检测的」
  • 如果没过期,则直接基于缓存信息渲染;
  • 如果没有或者过期了,那么需要重复上一步;
  • 不管是否走缓存,HTTP 状态码都是 200

强缓存的优点
减少对服务器的请求,加载资源速度更快,页面渲染速度更快

强缓存存在的问题?
客户端缓存信息了,但是服务器的资源文件更新了,比如:项目新版本上线部署,这样导致用户无法及时获取到服务器最新资源信息,也就是说:缓存时间没有到达,服务器更新之后,客户端无法及时更新,因为它拿的一直是缓存中的信息

一般情况下,xxx.html这种页面是不进行强缓存的,HTML 缓存之后,用户用的也是老版本。

所以,每一次 HTML 都是从服务器获取的;内容有更新,也会及时的在客户端更新渲染

如果其它资源文件服务器有更新,我们只需要在 HTML 中导入资源的时候做处理,三种方案:

  • 开发者手动加时间戳,手动修改时间戳:index.css?20201201220712
  • 资源文件的名字在内容发生更改后,名字重新生成:HASH 值「webpack 配置后可自动生成的」:index.css/fsfdsfs/.css
  • 基于协商缓存实现「一般项目中,两者都是同时设置的」

强缓存的处理

  • 强缓存是服务器设置的「Nginx 这些发布工具直接搞定」,并且基于响应头信息「Response Headers」返回给客户端的「cache-control: max-age=259200」,客户端浏览器接收到响应后,会自己建立缓存机制,不需要前端自己写代码
  • 服务器设定了一些资源「静态资源:html/css/js/图片…」的强缓存机制,在浏览器缓存的有效期内,排除手动清缓存刷新的情况,正常加载页面,都是从缓存中获取数据,而不是从服务器重新获取

协商缓存「Last-Modified/ETag」

协商缓存:协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发起请求,有服务器根据缓存标识决定是否使用缓存的过程

协商缓存的字段说明

  • Last-Modified:服务器上的最后修改时间

    • If-Modified-Since: Tue, 02 Apr 2019 04:33:32 GMT
    • HTTP1.0 版本使用字段
    • 服务器端返回资源时,响应头中设置 Last-Modified;客户端需要在请求头中添加:If-Modified-Since 请求头,值为 Last-Modified 中存储的值
  • ETag:由服务器端生成的唯一标识

    • If-None-Match: “700e28-17667-58584a3b7eca0”
    • HTTP1.1 版本使用字段
    • ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成);客户端需要在请求头中添加 If-None-Match

浏览器协商缓存的目的
校验资源文件是否更改:

  • 有更改从服务器拿最新的资源,拿到之后缓存到本地
  • 没有更改,服务器什么都不返回,客户端再从本地拿缓存信息
  • 哪怕本地有缓存也需要向服务器发请求

浏览器协商缓存的过程

客户端需要和服务器协商,在强缓存失效的情况下,协商缓存的机制才会触发,下面默认为没有强缓存或者强缓存失效的情况:

Last-Modified和If-Modified-Since

  • 第一次请求资源,没有任何缓存,服务器返回资源的同时「状态码返回的是200」,响应头中设置 Last-Modified,浏览器接收后,缓存文件资源和响应头、页面渲染

    在项目文件部署的时候,会生成 Last-Modified 对应的值,这个值代表当前项目文件在服务器上最后一次修改时间

  • 第N次请求这个资源,浏览器会先检测本地是否有存储的标识:Last-Modified
    • 如果没有认为没缓存,重复上一个步骤
    • 如果有:基于标识 If-Modified-Since,把之前存储的 Last-Modified 结果,传递给服务器「服务器要做的事情,不需要写代码,浏览器帮我们做了」
    • 服务器接收到结这个资源请求,会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比:
      • 如果没变化,说明文件没有更新,给客户端直接返回 304 状态码和空的响应体
      • 如果 If-Modified-Since 的时间小于服务器中这个资源的最后修改时间,就是说明文件有更新,给客户端直接返回 200 状态码和新的资源文件
    • 客户端收到响应后,判断状态码
      • 304:从缓存中获取文件资源,进行渲染
      • 200:渲染新的资源文件,并同时更新本地的缓存

ETag和If-None-Match

  • 第一次请求资源,服务器返回资源的同时「状态码返回的是200」,响应头中设置 ETag,浏览器接收后,缓存文件资源和响应头、页面渲染

    ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,ETag就会重新生成

  • 第N次请求这个资源,浏览器会先检测本地是否有存储的标识:ETag
    • 如果没有认为没缓存,重复上一个步骤
    • 如果有:会将上一次返回的 ETa g值放到请求头 If-None-Match 里,传递给服务器
    • 服务器需要比较客户端传来的 If-None-Match 跟自己服务器上该资源的 ETag 是否一致
      • 如果相同,说明文件没有更新,给客户端直接返回 304 状态码和空的响应体
      • 如果不相同,说明文件有更新,给客户端直接返回 200 状态码和新的资源文件
    • 客户端收到响应后,判断状态码
      • 304:从缓存中获取文件资源,进行渲染
      • 200:渲染新的资源文件,并同时更新本地的缓存

协商缓存的好处

  • html页面完全可以设置协商缓存,可以实现同步更新;
  • 除了 HTML,其他资源文件一般都是强缓存和协商缓存都做;
  • 对于经常更新的静态资源文件,可以不作缓存

性能优化

合理的利用缓存,可以提高 HTTP 网络层的优化

3. DNS 解析

DNS 服务器

DNS 服务器

也叫做域名解析服务器,部署服务器后,服务器有一个外网 IP 地址,基于外网 IP 可以找到服务器。这样能更快速的让客户记住网站的域名

域名解析服务器 DNS

记录了域名主机地址「外网 IP 」相对应的记录信息

DNS 解析

根据浏览器识别出来的 URL 地址中的域名,到 DNS 服务器上,查找服务器外网 IP 的过程

DNS 解析的过程

DNS 服务器上包含了解析线路「哪个域名对应哪个主机 IP 」,URL 解析完知道域名之后,首先要到 DNS 服务器上,通过到 DNS 服务器上找到当前域名所对应的服务器外网 IP 和服务器主机地址,通过主机地址找到我们的服务器

DNS 解析的时间

  • 每一次 DNS 解析时间预计在 20~120 毫秒
  • 在此期间要做的事情:
    • 第一次请求:www.baidu.com 从来没有解析过,需要 20~120 毫秒之间从头解析一遍
    • 第一次请求完,当前的 DNS 解析记录会缓存下来「浏览器默认」
    • 第二次请求根据查询方式,来进行查询

DNS 解析优化

  • 我们尽可能少去请求不同的服务器/域名,从而减少 DNS 的解析次数「这是一个被舍弃的方案」

    • 弊端:增加了 DNS 解析的时间

    • 优势

      • 合理的服务器资源分配
      • 抗压能力加强
      • 提高并发「每一台服务器的并发是有上限的」
      • HTTP 并发性「受源的限制」:每一个源下,可以一次最多允许的 HTTP 并发数:6~7 个,分开部署,就会存在很多的源,同时可以并发的 HTTP 数量也会增多,这样也是有助于页面渲染速度的
    • 资源一般都是部署到不同的服务器上「尤其是大项目」

      • 常见的服务器
      • web 资源服务器:存放的是 HTML、CSS、JS…
      • 图片资源服务器:存放的是 img、音视频…
      • 数据接口服务器:存放的是后台程序、数据库…
      • 第三方服务器:调取第三方服务器中的 API…
  • 减少 DNS 请求次数:在不能减少 DNS 解析记录的情况下,我们可以把 DNS 预解析,预先解析完成后缓存起来

    • 预解析:GUI 渲染和解析同时进行,不会等到渲染的这一步再去解析,边渲染边解析,渲染到某处,可能解析已经完成了
    • DNS 预获取「预解析」:DNS Prefetch <link rel = 'dns-prefetch' href='' />
      • 利用 link 的异步加载,每一个 link 都是一个新的 HTTP 线程,不会影响 GUI 线程的渲染
      • 在 GUI 线程渲染页面的同时,去实现 DNS 解析
      • 当 GUI 渲染到某部分,需要请求外部资源,但是此时我们已经解析过了,不用再去重新解析…
      • 发送一个「多个」预解析的请求,浏览器分配一个「多个」单独的线程去做预解析,GUI 线程才会继续往下走,不会影响 GUI 渲染进程, GUI 渲染的同时,预解析也在执行,预解析完成之后,会存在缓存
查询 DNS 解析的两种方式

浏览器解析过一次,一般就会在本地缓存解析记录,所以每一次 DNS 解析都要经历两个过程:

  • 递归查询:本地 DNS 服务器,通过递归查询的方式查看本地缓存的解析记录
  • 迭代查询:本地 DNS 服务器没有的话,通过根域名服务器、顶级域名服务器、权威域名服务器上,通过迭代查询的方式查看本地缓存的解析记录

递归查询:

递归查询的过程:

  • 客户端发请求的时候,查看浏览器中是否有缓存,如果浏览器中把 DNS 信息缓存下来了,直接从浏览器中拿过来
  • 如果浏览器中没有,查看本地的 hosts 文件「通过配置 hosts 文件,可以影响网络请求」,如果有直接拿过来
  • 如果 hosts 文件中没有,在查看本地 DNS 解析器缓存中有没有,有直接拿过来
  • 如果没有,在查看本地 DNS 服务器中查找

递归查询的优点: 有缓存速度会很快

迭代查询:如果本地缓存中不存在那么使用迭代查询的方式来进行查询

迭代查询的过程

  • 本地 DNS 服务器中没有,查找根域名服务器
  • 拿到信息返回给 DNS 服务器,接着查找顶级域名服务器
  • 拿到一些信息后,在去权威域名服务器中查找,拿到一些信息
  • 把这些服务器都走完之后,才能找到主机 ID
  • 拿到主机 ID 返回给 DNS 服务器后会进行一个本地缓存,
  • DNS 服务器再去返回给客户端,由客户端去发送请求,而不是通过 DNS 服务器直接发送请求

性能优化

DNS 优化方案:

  • 减少DNS请求次数
  • DNS 预获取/预解析(DNS Prefetch)

4. TCP 三次握手

字段介绍

  • 序号
    • seq 序号:用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记
  • 确认序号
    • ack:确认序号,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1
  • 标志位
    • ACK:确认序号有效
    • RST:重置连接
    • SYN:发起一个新连接
    • FIN:释放一个连接

什么是 TCP
TCP提供了一种可靠、面向连接、字节流、传输层的服务,采用三次握手建立一个连接。采用4次挥手来关闭一个连接。保证了通信的稳定性
UDP 和 TCP 的区别

  • UDP 不需要做校验,直接发送请求
    • 优点:速度块
    • 弊端:不稳定,不会有三次握手这样的机制
  • TCP 稳定可靠的通信协议「最常用的」
    • 优点:稳定
    • 弊端就是速度慢

TCP 三次握手的目的

  • TCP 三次握手,建立客户端和服务器之间的连接通道
  • TCP 三次握手后:客户端基于 HTTP 把数据传递给服务器「HTTP 是在通道上传递东西的」

三次握手的过程

  • 第一次握手:客户端向服务器发送请求
  • 第二次握手:服务器接收到请求之后,给客户端一个应答:我已经成功接收请求,准备好了在给你
  • 第三次握手:客户端接收到消息后,给服务器一个应答:我接收到了你的消息,并且我也能知道你也成功接收到了我的消息

为什么不用两次或者四次?
第一、二次握手后,服务端并不知道客户端的接收能力以及自己的发送能力是否正常。而在第三次握手时,服务端收到了客户端对第二次握手作的回应。从服务端的角度,我在第二次握手时的响应数据发送出去了,客户端接收到了。所以,我的发送能力是正常的。而客户端的接收能力也是正常的。

5. 数据传输

  • HTTP 报文:所有客户端和服务器端传输的信息,统称为报文
    • 请求报文
    • 响应报文
  • 响应状态码
    • 200 OK
    • 202 Accepted :服务器已接受请求,但尚未处理(异步)
    • 204 No Content:服务器成功处理了请求,但不需要返回任何实体内容
    • 206 Partial Content:服务器已经成功处理了部分 GET 请求(断点续传 Range/If-Range/Content-Range/Content-Type:”multipart/byteranges”/Content-Length….)
    • 301 Moved Permanently
    • 302 Move Temporarily
    • 304 Not Modified
    • 305 Use Proxy
    • 400 Bad Request : 请求参数有误
    • 401 Unauthorized:权限(Authorization)
    • 404 Not Found
    • 405 Method Not Allowed
    • 408 Request Timeout
    • 500 Internal Server Error
    • 503 Service Unavailable
    • 505 HTTP Version Not Supported
      ……
  • 并发性

6. TCP 四次挥手

什么是 TCP 四次挥手
关闭通道,同时发起 TCP 的四次挥手
四次挥手的过程

  • 第一次:客户端向服务器发送请求,给服务器说一声:给你了「应答」
  • 第二次:服务器我收到了,准备好之后给你
  • 第三次:服务器:我准备好了,发给你了,你接收吧
  • 第四次:给服务器说一声:收到了;处理数据

TCP 三次握手/四次挥手的优化
每一次客户端和服务器的请求,如果都需要 TCP 三次握手和四次挥手,那么每一次都需要消耗一些时间

因此,在 HTTP1.1 中提供的属性:Connection:keep-alive「由服务器端设置的(HTTP1.1 版本默认添加,HTTP1.0 版本需要手动添加)」

Connection:keep-alive
保持 TCP 连接「长连接」

第一次发送请求,通过三次握手建立通道,在一定时间内通道是不会关闭,可以让当前客户端在这个通道之内发送多次请求,服务器把多次请求的内容返回给客户端,就不会再建立三次握手和四次挥手,超过时间则会重新建立连接

为什么连接的时候是三次握手,关闭的时候却是四次握手?
服务器端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文

但关闭连接时,当服务器端收到FIN报文时,很可能并不会立即关闭连接,所以只能先回复一个ACK报文,告诉客户端:”你发的FIN报文我收到了”,只有等到服务器端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送,故需要四步握手。

7. 页面渲染

  • 从服务器基于 HTTP/HTTPS 网络请求回来的数据,是一个 16 进制的文件流:
    • 浏览器把它解析成字符串「HTML 字符串」
    • 按照 W3C 规则识别成为一个个的节点「词法解析」
    • 按照层级结构,生成一个DOM 树「HTML」/ CSSOM 树「CSS」
    • 将 DOM 树和 CSSOM 树融合成渲染树
    • 根据生成的渲染树,计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流「布局(Layout)或 重排(reflow)」
    • 根据渲染树以及回流得到的几何信息,得到节点的绝对像素「绘制(painting)」
  • 访问页面:首先请求回来的是一个 HTML 文档,浏览器开始自上而下(解析和识别代码)渲染「执行字符串代码」

Ending

虽然还有一些要完善的地方,但是你搞懂了这些,面试轻轻松松… 吗咿呀嘿 吗咿呀嘿~

特别提醒:如有误请及时提出给与改正,感谢~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值