一次完整的HTTP请求页面过程是怎么样的呢?

参考

一次完整的HTTP请求过程是怎么样的呢?
浏览器中输入一个url到显示页面全过程

前言

完整页面初始化构建流程(不包含生命周期函数请求后端数据)

Web浏览器(URL,生成request请求信息)→网络控制软件/协议栈(消息层层打包,加目的地等控制信息,交网卡)+网卡(数据包转化电信号(->光信号),通过网线或光纤发送)→集线器+交换机+路由器(进入背后的互联网)→接入网(通信线路)+网络运营商基站(接入接入点的设备/POP/路由,进入骨干网到达Web服务器的局域网)→防火墙(检查非法包)+缓存服务器(存放重复利用数据)+负载均衡器(消息发到多个Web服务器)→Web服务器(层层解包为请求信息,交给程序)→反向推送response响应→浏览器读取response数据并显示。
———————————————— 版权声明:本文为CSDN博主「QLUGCL」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43813373/article/details/125023105

浏览器接受URL到页面呈现的过程包括URL解析、网络请求、接收HTML文件、构建DOM树、请求和解析外部资源、构建CSSOM树、构建渲染树、布局、绘制和显示页面。这些过程中,DOM树、CSSOM树和渲染树扮演着重要的角色,协同工作来实现网页的渲染和呈现。

在这里插入图片描述

基础知识

完整页面=页面URL(HTML框架页面(包含umi页面路由)+资源请求路径(src=…js/css))+资源文件(js,css)
网络请求获取前端静态资源(html+css/js等),(元素)浏览器将资源包整合为完整原生html展示(源代码)。
DOM树+CSSOM树=渲染树(所有资源文件由浏览器整合为完整原生html代码后再展示为html页面给用户)
在这里插入图片描述
Chrome中开发者工具的功能面板常用功能介绍

  • 元素:用于查看网页中完整的html结构与css样式;(渲染树)
  • 控制台:浏览器中输入控制台信息,js脚本执行过程中,输出执行状态可以在控制台查看;
  • 源代码:源代码与静态资源,进行网站源代码的调试、查看、编辑;
  • 网络:每一个网站都有后台web服务器,网站前端与服务器 http 交互过程中,可以查看网络日志,可以查看调试;
  • 应用:查看网页的缓存信息,如 cookie、localStorage等;

浏览器展示完整的页面的流程

首先触发URL发出http请求得到URL对应源代码(react,vue)经过编译打包的HTML框架页面(包含umi页面路由)。

类型一
页面路由信息配置文件(浏览器运行)

<script src="/source/umi.573c6a85.js"></script>
<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="icon" href="/source/previewLogo.png" type="image/x-icon" />
    <link rel="stylesheet" href="/source/umi.451611c7.css" />
    <script>
      window.routerBase = "/";
    </script>
    <script>
      //! umi version: 3.5.20
    </script>
  </head>
  <body>
    <div></div>
    <div id="root"></div>
    <script src="/source/umi.573c6a85.js"></script>
  </body>
</html>

类型二

<a href="https://i.csdn.net/#/user-center/profile" target="_blank" data-report-click="{&quot;spm&quot;:&quot;3001.5516&quot;}" data-report-query="spm=3001.5516" class="user-profile-black-btn" data-v-d1dbb6f8>
<img src="https://csdnimg.cn/release/cmsfe/public/img/icon-edit-new.065a6914.png" alt class="bt-icon" data-v-d1dbb6f8>编辑资料
</a>

然后根据HTML框架页面(包含umi页面路由)的资源标签中的资源链接再次发出http请求获取静态资源文件。
注意:静态资源链接分为两种(react中可以用publicPath来指定静态资源链接的根路径)

相对路径=>父容器的http://ip:port+相对路径组合为完整请求路径。
绝对路径=>直接发出请求静态资源文件。

publicPath:'/xxx/'或‘http://ip:port/xxx/’
作用:指定在浏览器中访问前端静态资源的基础根路径----相对路径或绝对路径.

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
网页前端内容都是从数据包的response的body和源码资源中提取的。
网页的全部信息以及资源都是基于数据包。

数据包中资源如图所示
在这里插入图片描述

选中后右键检查元素,直接定位对应源代码。
在这里插入图片描述

概述

  • 浏览器进行DNS域名解析,得到对应的IP地址
  • 根据这个IP,找到对应的服务器建立连接(三次握手)
  • 建立TCP连接后发起HTTP请求(一个完整的http请求报文)
  • 服务器响应HTTP请求,浏览器得到html代码(服务器如何响应)
  • 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)
  • 浏览器对全部资源包进行渲染呈现给用户页面
  • 服务器关闭TCP连接(四次挥手)

window对象
在Web开发中,window对象是浏览器窗口的顶层对象,它代表浏览器窗口本身。window对象是一个全局对象,所有的JavaScript代码都可以通过window对象来访问浏览器窗口的属性和方法。
先创建window对象再解析创建Dom树。
window对象的创建过程:

  1. 浏览器启动:当浏览器启动并加载一个网页时,它会创建一个window对象,一个网页标签一个window对象。
  2. 网页加载
    • 当网页的HTML被加载时,浏览器会解析HTML文档,并找到包含JavaScript代码的部分。
    • JavaScript引擎(如Chrome的V8引擎)将会执行这些JavaScript代码。
  3. DOM树构建
    • 同时,浏览器正在构建DOM(Document Object Model)树,这是网页内容的逻辑结构。
  4. JavaScript执行
    • 如果在JavaScript代码中直接或间接地引用了window对象(例如通过全局变量或者函数参数),那么这个引用将自动指向当前正在加载的网页的window对象。
    • 如果在JavaScript中显式地创建一个新的window对象,那么这个新对象将与当前的window对象是同一个实例。

过程详解

所谓的‘三颗树’

在浏览器中,当解析和加载网页时,会形成三个重要的树结构:DOM树、CSSOM树和渲染树(Render Tree)。这些树结构在网页的渲染和布局过程中起到关键作用。

DOM树(Document Object Model Tree): DOM树表示HTML文档的结构,它由浏览器解析HTML代码生成。DOM树以层次结构的方式表示文档中的HTML元素(例如<html>、<body>、<div>等),每个元素都是DOM树的节点。DOM树包括元素节点、文本节点、注释节点等。DOM树反映了HTML文档的层次结构和标记嵌套关系。

CSSOM树(CSS Object Model Tree): CSSOM树表示CSS样式规则的层次结构。它由浏览器解析CSS文件和嵌入式样式,并将它们转化为树形结构。CSSOM树包含了网页中所有的CSS规则,如选择器、样式属性等。CSSOM树和DOM树是相互独立的,但是它们通过元素的匹配来建立关联。

渲染树(Render Tree): 渲染树是将DOM树和CSSOM树合并后的结果。它是浏览器用于渲染页面的关键结构。渲染树中的每个节点被称为渲染对象,它包括了页面上需要显示的所有元素(如可见元素、盒子模型等)以及与之相关的样式信息。渲染树中的每个节点都有布局和绘制信息,用于确定元素在页面上的位置和外观。

渲染树的生成过程如下:

浏览器解析HTML代码并构建DOM树。
浏览器解析CSS代码并构建CSSOM树。
将DOM树和CSSOM树进行合并,生成渲染树。
根据渲染树进行布局(确定元素的大小和位置)。
根据渲染树进行绘制(绘制页面上的每个元素)。

渲染树的生成过程中,浏览器会根据CSS规则和DOM结构进行计算,确定哪些节点应该在渲染树中显示,哪些节点应该被忽略(例如隐藏的元素、不可见的元素等)。这样可以提高渲染性能,并确保只绘制页面上需要显示的内容。

通过渲染树,浏览器可以快速确定需要渲染和显示的元素,然后进行布局和绘制,最终呈现给用户。
总结

  • 获取Html页面文档结构。
  • 解析Html文件构造Dom树并请求Html文件中资源标签涉及的css,js等资源文件
  • 解析css资源文件构造CSSOM树
  • Dom树+CSSOM树=>渲染树(所有资源文件由浏览器整合为完整原生html代码)
    在这里插入图片描述

在这里插入图片描述

一、DNS解析

  • 首先会搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存)
  • 如果浏览器自身的缓存里面没有找到,那么浏览器会搜索系统自身的DNS缓存
  • 如果还没有找到,那么尝试从 hosts文件里面去找

在前面三个过程都没获取到的情况下,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求(通过的是UDP协议向DNS的53端口发起请求,这个请求是递归的请求,也就是运营商的DNS服务器必须得提供给我们该域名的IP地址)

在这里插入图片描述

二、TCP三次握手

在这里插入图片描述
三次握手完成之后这个TCP连接就进入Established状态,就可以发起http请求了。

【问题1】:TCP 为什么需要3次握手?

2个计算机通信是靠协议(目前流行的TCP/IP协议)来实现,如果2个计算机使用的协议不一样,那是不能进行通信的,所以这个3次握手就相当于试探一下对方是否遵循TCP/IP协议,协商完成后就可以进行通信了,当然这样理解不是那么准确。

【问题2】:为什么HTTP协议要基于TCP来实现?

目前在Internet中所有的传输都是通过TCP/IP进行的,HTTP协议作为TCP/IP模型中应用层的协议也不例外,TCP是一个端到端的可靠的面向连接的协议,所以HTTP基于传输层TCP协议不用担心数据的传输的各种问题。

三、发起HTTP请求

HTTP是一个客户端和服务器端请求和应答的标准(TCP)。客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求。

通俗来讲,他就是计算机通过网络进行通信的规则,是一个基于请求与响应,无状态的,应用层的协议,常基于TCP/IP协议传输数据。目前任何终端(手机,笔记本电脑。。)之间进行任何一种通信都必须按照Http协议进行,否则无法连接。
在这里插入图片描述
一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成,下图给出了请求报文的一般格式。
在这里插入图片描述
请求行:用于描述客户端的请求方式(GET/POST等),请求的资源名称(URL)以及使用的HTTP协议的版本号。
它们用空格分隔。例如,GET /index.html HTTP/1.1。
HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。
GET是最常见的一种请求方式,当客户端要从服务器中读取文档时,当点击网页上的链接或者通过在浏览器的地址栏输入网址来浏览网页的,使用的都是GET方式。GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端。 POST方法可以允许客户端给服务器提供信息较多。POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,这样POST方式对传送的数据大小没有限制,而且也不会显示在URL中,对隐私数据保密性更好。 HEAD就像GET,只不过服务端接受到HEAD请求后只返回响应头,而不会发送响应内容。当我们只需要查看某个页面的状态的时候,使用HEAD是非常高效的,因为在传输的过程中省去了页面内容。
请求头:请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
User-Agent:产生请求的浏览器类型。 Accept:客户端可识别的内容类型列表。 Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。 Connection 告诉服务器支持keep-alive特性 Cookie 每次请求时都会携带上Cookie以方便服务器端识别是否是同一个客户端
空行:最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
请求数据:当使用POST等方法时,通常需要客户端向服务器传递数据。这些数据就储存在请求正文中(GET方式是保存在url地址后面,不会放到这里)。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。
【问题3】:那什么是URL、URI、URN?

URI Uniform Resource Identifier 统一资源标识符
URL Uniform Resource Locator 统一资源定位符
URN Uniform Resource Name 统一资源名称

URL和URN 都属于 URI,为了方便就把URL和URI暂时都通指一个东西。

发起网络请求:

浏览器使用解析后的URL信息,通过网络发送HTTP请求到服务器,请求获取网页的HTML文件。这个过程涉及到TCP连接(即连接时三次握手,断开时四次挥手),连接成功后就发送HTTP请求等操作,具体如下

发起网络请求是指浏览器向服务器发送请求以获取网页资源的过程。以下是发起网络请求的详细过程:

(1). 建立与服务器的连接: 浏览器使用解析后的主机名和端口号(如果有)建立与目标服务器的网络连接。它可以是TCP连接或TLS(Transport Layer Security)连接,具体取决于使用的协议(如HTTP或HTTPS)。

(2). 创建请求报文: 浏览器构建一个包含请求信息的请求报文。请求报文包括请求行、请求头和请求主体。请求行包含请求的方法(如GET、POST)、路径和协议版本。请求头包含与请求相关的附加信息,如用户代理、Accept-Encoding(用于指定支持的内容编码)、Cookies等。请求主体包含在POST请求中发送的数据。

(3). 发送请求报文: 浏览器将构建好的请求报文发送给服务器。它通过网络连接将请求报文作为数据包发送出去。数据包通过互联网的网络基础设施传输到目标服务器。

(4). 服务器接收请求报文: 目标服务器接收到请求报文,并进行相应的处理。服务器会解析请求报文,提取出请求的目标资源和相关信息。

(5). 处理请求: 服务器根据请求报文中的信息,处理请求并准备相应的响应。这可能涉及访问数据库、运行服务器端脚本等操作,以生成响应内容。

(6). 创建响应报文: 服务器构建一个包含响应信息的响应报文。响应报文包括状态行、响应头和响应主体。状态行包含响应的状态码(如200表示成功、404表示资源未找到等)和协议版本。响应头包含与响应相关的附加信息,如内容类型、日期、缓存控制等。响应主体包含服务器返回的数据。

(7). 发送响应报文: 服务器将构建好的响应报文发送回浏览器。响应报文通过网络连接传输回浏览器。

(8). 浏览器接收响应报文: 浏览器接收到服务器发送的响应报文。它读取响应报文中的状态码和头信息,并根据这些信息进行相应的处理。

(9). 处理响应: 浏览器根据响应报文中的信息进行处理。这可能包括解析响应数据、执行JavaScript代码、更新页面内容等操作。

(10). 渲染页面: 如果响应中包含HTML文档,浏览器会解析HTML并构建DOM树、CSSOM树和渲染树,然后进行布局和绘制,最终将页面内容呈现给用户。

四、服务器响应HTTP请求

接收到HTTP请求之后,就轮到负载均衡登场了,它位于网站的最前端,把短时间内较高的访问量分摊到不同机器上处理。负载均衡方案有软件、硬件两种。软件方案常见的就是NGINX了。

Nginx的作用主要有两个:
1,处理静态文件请求。
2,转发请求给后端服务器。
然后后端服务器查询数据库返回数据。数据返回给客户端仍然通过HTTP协议传输。

HTTP响应报文主要由状态行、响应头部、空行以及响应数据组成。

  • 状态行:由3部分组成,分别为:协议版本,状态码,状态码描述。

其中协议版本与请求报文一致,状态码描述是对状态码的简单描述,所以这里就只介绍状态码。

一些常见的状态码如下:

状态代码为3位数字。

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

  • 响应头:响应头用于描述服务器的基本信息,以及客户端如何处理数据
  • 空格:CRLF(即 \r\n)分割
  • 消息体:服务器返回给客户端的数据

在这里插入图片描述
上面的 HTTP 响应中,响应头中的 Content-Length 同样用于表示消息体的字节数。Content-Type 表示消息体的类型,通常浏览网页其类型是HTML,当然还会有其他类型,比如图片、视频等。

接收HTML文件:

服务器接收到浏览器的请求后,将网页的HTML文件作为响应发送给浏览器。
构建DOM树

Nginx代理前端资源文件+后端数据请求路径

底层逻辑:根据最终NG代理的地址寻找资源,地址信息(IP:PORT,URL等)。
外部IP:PORT先根据IP找到容器然后触发Nginx监听的端口后,会进行location映射代理到对应的url路径访问前端资源或后端数据请求
Nginx的工作原理就是被动被暴露的IP:PORT触发监听端口后代理到对应的URL请求资源(前端或后端)。
容器中会将访问端口设置为Nginx的监听端口这样就能实现Nginx代理容器所有请求(自身静态资源页面请求和后端数据请求等)。

必须主动触发Nginx监听的端口才能实现Nginx代理
IP:PORT-IP定位Nginx所在容器,PORT触发Nginx监听代理。

IP:定位容器
PORT:触发Nginx监听端口

在这里插入图片描述
前端运行环境区别
本地都是编译打包跑在Node上,容器是npm run build编译打包资源放到内存由Nginx代理Url请求前端静态资源。
前端容器只跑了一个NG,其余的是静态资源存储在容器内存中,NG代理转发静态资源,最终由用户浏览器加载解析运行页面。
前端工程先npm install下载package.json中依赖和命令脚本(npm start等命令)为node_modules再将其中的依赖和页面等npm run build(webpack)编译打包为资源文件夹.
npm run build=node_modules依赖+src,config等工程文件=编译打包为一个一个资源文件包(可通过analyze查看每个包的原始路径就能看到有的根路径是node_modules有的是src)

Nginx并不负责编译运行代码只负责代理转发url请求原生代码页面资源,最终浏览器编译运行原生代码页面,出错会在浏览器控制台console报出来。
浏览器运行打包好的umi.js等资源文件实现路由映射等功能。

在这里插入图片描述

五、浏览器请求资源包–对应第二节内容

一个页面需要多个http请求获取多个资源包(html,css,js等)整合解析为一个完整的页面
在这里插入图片描述

浏览器拿到index.html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,就向服务器端去请求下载(请求资源包会使用多线程并行下载,每个浏览器的线程数不一样),这个时候就用上keep-alive特性了,建立一次HTTP连接,可以请求多个资源,下载资源的顺序就是按照代码里的顺序,但是由于每个资源大小不一样,而浏览器又多线程请求请求资源,所以从下图看出,这里显示的顺序并不一定是代码里面的顺序。
缓存
浏览器在请求静态资源时(在未过期的情况下),向服务器端发起一个http请求(询问自从上一次修改时间到现在有没有对资源进行修改),如果服务器端返回304状态码(告诉浏览器服务器端没有修改),那么浏览器会直接读取本地的该资源的缓存文件。

在这里插入图片描述

六、浏览器解析资源包:DOM树+CSSOM树=渲染树(所有资源文件由浏览器整合为完整原生html代码)

构建DOM树是将HTML文档解析并转换为DOM树的过程。
解析html架构且并行请求css,js静态资源文件

浏览器利用自己内部的工作机制,把请求的(css,js等)静态资源和html代码进行渲染,渲染之后呈现给用户,浏览器是一个边解析边渲染的过程。
浏览器开始解析接收到的HTML文件,并构建DOM树。它从HTML的根元素开始,逐步解析和构建所有HTML元素及其嵌套关系。

首先浏览器解析HTML文件构建DOM树,然后解析CSS文件构建CSSOM树,最后二者合并构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。

在这里插入图片描述

如何构建DOM树

构建DOM树是将HTML文档解析并转换为DOM树的过程。
DOM树表示了HTML文档的层次结构,每个HTML元素都在DOM树中表示为一个节点。以下是构建DOM树的详细过程:

(1). 标记化(Tokenization): 浏览器接收到HTML文档后,首先会进行标记化处理。标记化将HTML文档分解为一系列的标记(Tokens),包括开始标签、结束标签、文本内容、注释等。标记化器根据HTML规范定义的规则进行解析,将文档分解为标记序列。

(2). 构建节点: 标记化器解析标记序列,并根据标记的类型构建DOM树的节点。开始标签和结束标签会被解析为元素节点(Element Nodes),文本内容会被解析为文本节点(Text Nodes),注释会被解析为注释节点(Comment Nodes)等。每个节点都包含其在DOM树中的位置、父节点、子节点和相关的属性。

(3). 关联节点: 在构建节点的过程中,解析器会根据标记之间的嵌套关系来建立节点之间的关联。例如,遇到一个开始标签时,解析器会将其作为一个元素节点,并将其作为上一个解析的节点的子节点。这样,通过嵌套关系,整个DOM树的结构逐步形成。

(4). 处理样式和脚本: 在构建DOM树的过程中,如果遇到

(5). 完成DOM树: 当解析器完成对整个HTML文档的解析和节点构建后,就形成了完整的DOM树。DOM树反映了HTML文档的层次结构和标记嵌套关系,每个节点代表一个HTML元素或其他类型的内容。

构建DOM树的过程是逐个解析标记并构建相应节点的过程,通过嵌套关系建立节点之间的父子关系。DOM树的构建过程为后续的页面渲染、样式应用、JavaScript操作等提供了基础。
请求和解析外部资源

在构建DOM树的过程中,浏览器会遇到外部资源,如CSS文件、JavaScript文件、图像等。浏览器会发起额外的网络请求来获取这些资源,并在接收到资源后解析和处理它们。

构建CSSOM树

当浏览器解析和接收CSS文件时,它会构建CSSOM树。CSSOM树表示CSS样式规则的层次结构,包括选择器、样式属性等。
如何构建CSSOM树

构建CSSOM树是将CSS样式规则解析并转换为CSSOM树的过程。CSSOM树表示CSS规则的层次结构,包括选择器、样式属性等。以下是构建CSSOM树的详细过程:

(1). 解析CSS文件: 浏览器在解析HTML文档时,会发现引用的CSS文件,并对其进行解析。浏览器会逐行读取CSS文件,并将其分解为一系列的CSS规则。

(2). 构建规则: 解析器将每个CSS规则解析为一个规则对象。一个规则对象包括一个选择器和一个声明块。选择器指定了应用该规则的元素,声明块包含了一组样式属性和对应的值。

(3). 构建选择器树: 解析器会将解析得到的选择器转换为选择器树。选择器树是一种表示选择器之间关系的树结构。根据选择器的嵌套关系,解析器会构建选择器树来表示选择器之间的层次结构和嵌套关系。

(4). 匹配元素: 浏览器会遍历DOM树中的每个元素,并根据元素的标签名、类名、ID等属性与CSS规则中的选择器进行匹配。如果元素与选择器匹配成功,那么该元素将被应用相应的样式。

(5). 构建样式规则: 当元素与选择器匹配成功后,浏览器会将匹配的样式规则与元素相关联。每个样式规则都包含了一组样式属性和对应的值。浏览器会将这些样式规则应用于匹配的元素。

(6). 构建CSSOM树: 在匹配并应用所有CSS规则后,浏览器将构建得到的样式规则以及与之相关联的元素,转换为CSSOM树。CSSOM树的结构与DOM树类似,每个节点表示一个样式规则,并包含其对应的样式属性和值。

(7). 处理样式继承: 在CSSOM树中,一些样式属性具有继承性,即子元素会继承父元素的样式。浏览器会处理样式继承,并确保子元素正确继承父元素的样式。

(8). 处理层叠样式: 如果多个CSS规则应用于同一个元素并定义了相同的样式属性,浏览器会根据层叠规则(如选择器的特殊性、样式规则的顺序等)来决定最终应用哪个样式。

通过构建CSSOM树,浏览器能够获取并组织CSS规则,并将其应用于对应的元素。这是实现

构建渲染树(资源文件整合后的HTML页面内容)

浏览器将DOM树和CSSOM树进行合并,生成渲染树。渲染树中只包含需要显示的元素和相关的样式信息,隐藏的元素不会被包括在渲染树中。
构建渲染树过程

构建渲染树是将DOM树和CSSOM树合并为一个渲染树的过程。渲染树是浏览器用于渲染页面的关键数据结构,它包含了需要显示的所有元素以及与之相关的样式信息。以下是构建渲染树的详细过程:

(1). 合并DOM树和CSSOM树: 浏览器将DOM树和CSSOM树进行合并。这是通过匹配DOM树中的每个元素节点与CSSOM树中的规则进行匹配来实现的。只有那些与DOM树中的元素节点匹配的CSS规则才会被包含在渲染树中。

(2). 忽略不可见元素: 渲染树只包含需要显示的元素,对于那些不可见的元素(如设置了display: none样式的元素、被隐藏的元素等),浏览器会将其从渲染树中移除。

(3). 计算样式: 渲染树中的每个节点都会计算最终的样式。这是通过继承和层叠规则来决定节点的最终样式。节点的样式计算包括计算盒子模型(如宽度、高度、边距等)以及其他相关的样式属性。

(4). 布局(Layout): 渲染树的每个节点都包含了布局(Layout)信息,用于确定节点在页面中的位置和大小。布局过程计算每个节点的几何属性,如位置、尺寸、边距等。布局是渲染树的一次遍历过程,确保每个节点都按正确的顺序布局,从而构建页面的准确结构。

(5). 绘制(Painting): 布局完成后,渲染树中的每个节点都包含了绘制(Painting)信息,用于绘制节点在屏幕上的外观。绘制过程将节点的样式属性转化为像素,并在屏幕上绘制出相应的图像。

(6). 显示页面: 当渲染树的节点完成绘制后,浏览器将把绘制好的图像显示在用户的屏幕上。这是通过操作系统和图形库来完成的。

渲染树的构建过程包括合并DOM树和CSSOM树、忽略不可见元素、计算样式、布局和绘制等步骤。它是浏览器渲染引擎将HTML和CSS转化为可视化页面的关键过程,确保正确显示页面的结构和样式。

七、浏览器进行页面渲染

最后,浏览器利用自己内部的工作机制,把请求的(css,js等)静态资源和html代码进行渲染,渲染之后呈现给用户,浏览器是一个边解析边渲染的过程。
浏览器开始解析接收到的HTML文件,并构建DOM树。它从HTML的根元素开始,逐步解析和构建所有HTML元素及其嵌套关系。

首先浏览器解析HTML文件构建DOM树,然后解析CSS文件构建CSSOM树,最后二者合并构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。

这个过程比较复杂,涉及到两个概念: reflow(回流)和repain(重绘)。DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。

页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。

JS的解析是由浏览器中的JS解析引擎完成的。JS是单线程运行,JS有可能修改DOM结构,意味着JS执行完成前,后续所有资源的下载是没有必要的,所以JS是单线程,会阻塞后续资源下载。

八、服务器关闭TCP连接

一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接。

而关闭TCP连接就需要进行四次挥手了。

中断连接端可以是客户端,也可以是服务器端。
在这里插入图片描述

  • 第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
  • 第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2
    状态,继续等待服务器端的FIN报文。
  • 第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
  • 第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。

上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,也是通过四次握手。

【问题4】为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

【问题5】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

然而如果浏览器或者服务器在其头信息加入了这行代码:

Connection:keep-alive

TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

自此一次完整的HTTP事务宣告完成。

原理和实践

拆包-快速展示页面(umi3.X-webpack5拆包)

底层原理是利用webpack实现拆包

底层原理:网络带宽(能同时请求的资源包总大小)能影响你现实体验的网速快慢。

umi.js打包配置优化
UmiJs - 拆包优化
知识前提:请求静态资源包会使用多线程并行下载,每个浏览器的线程数不一样。
提升首屏加载时间原理:把大体积的包,分成多个小体积的包进行按需并行加载,减少请求时间(以最大包请求时间为准)
因为:页面加载Js是并行多个加载的,所以若资源包大小不均匀,一个js大小2M,一个大小100KB,那么最后页面加载的时间还是以最长的2M为准。
反之,如果你均分成两个1M大小的文件,那么页面加载JS的时长就是加载1M资源包的时长。
F12事实证明:浏览器并行请求静态资源(css,js等)
在这里插入图片描述

我们在写前端代码的时候,难以避免的是,我们可能引入的依赖越来越多。那么随之而来的,我们打包编译后的产物,也会随之越来越大。
默认情况下,使用Umi框架的人都知道,Umi会将前端页面,凡是用到的依赖都给打包到umi.js文件。同样地,CSS相关的则打入umi.css文件中。那当你的项目达到一定规模或者复杂程度上去的时候,尤其是umi.js文件就会很大。

在这里插入图片描述
在这里插入图片描述

拆包步骤:
  • 查看依赖包大小分布页面
"scripts": {
	"analyze": "cross-env ANALYZE=1 umi build",
}
npm run analyze

在这里插入图片描述

  • 查看较大的依赖包中的包,那些比较大,拆出来
    包名:@antv
    路径:Path
    在这里插入图片描述

  • 编写拆包公式-webpack5

defineName: {
                    name: '包名',
                    test: /[\\/]node_modules[\\/]fatherPath[\\/](包名)[\\/]/,
                    priority: -9,
                    enforce: true,
                },

注意:被拆包的fatherPath不能被拆会改变名称会导致找不到被拆包的最终拆包路径。
例如:
echarts不能拆否则会改变名称导致map文件找不到

                map: {
                    name: 'map',
                    test: /[\\/]node_modules[\\/]echarts[\\/](map)[\\/]/,
                    priority: -9,
                    enforce: true,
                },

在这里插入图片描述

在这里插入图片描述

代码

config.js
首先配置chainWebpack和待拆包名称chunks-要和包名一致

import webpackplugin from './plugin.config';
export default {
  
plugins: [
    [
      'umi-plugin-react',
      {
        dynamicImport: {
          loadingComponent: './components/PageLoading/index',
        },
          chunks: ['vendors', 'antd','@antv','react', 'react-dom', 'umi','map','lib'],
      },
    ],
    ['@umijs/plugin-qiankun'],
  ],
  chainWebpack: webpackplugin,
}

plugin.config
配置待拆包的路径,拆包。

import path from 'path';

export default config => {
    config.optimization
        .runtimeChunk(false)
        .splitChunks({
            chunks: 'all',
            automaticNameDelimiter: '~',
            name: true,
            minSize: 10000, // 将最小大小减小到10kb
            minChunks: 1,
            cacheGroups: {
                react: {
                    name: 'react',
                    test: /[\\/]node_modules[\\/](react)[\\/]/,
                    priority: -9,
                    enforce: true,
                },
                reactDom: {
                    name: 'react-dom',
                    test: /[\\/]node_modules[\\/](react-dom)[\\/]/,
                    priority: -9,
                    enforce: true,
                },
                antv: {
                    name: '@antv',
                    test: /[\\/]node_modules[\\/](@antv)[\\/]/,
                    priority: -9,
                    enforce: true,
                },
                map: {
                    name: 'map',
                    test: /[\\/]node_modules[\\/]echarts[\\/](map)[\\/]/,
                    priority: -9,
                    enforce: true,
                },
                lib: {
                    name: 'lib',
                    test: /[\\/]node_modules[\\/]echarts[\\/](lib)[\\/]/,
                    priority: -9,
                    enforce: true,
                },
                antd: {
                    name: 'antd',
                    test: /[\\/]node_modules[\\/](@ant-design|antd|antd-mobile)[\\/]/,
                    priority: -10,
                    enforce: true,
                },
                vendors: {
                    name: 'vendors',
                    test: /[\\/]node_modules[\\/]/,
                    priority: -12,
                    enforce: true,
                },
            },
        });
};

Nginx代理前端资源文件+后端数据请求路径

前端必备的nginx知识点
底层逻辑:根据最终NG代理的地址寻找资源,地址信息(IP:PORT,URL等)。
外部IP:PORT先根据IP找到容器然后触发Nginx监听的端口后,会进行location映射代理到对应的url路径访问前端资源或后端数据请求

Nginx的工作原理就是被动被暴露的IP:PORT触发监听端口后代理到对应的URL请求资源(前端或后端)。
容器中会将访问端口设置为Nginx的监听端口这样就能实现Nginx代理容器所有请求(自身静态资源页面请求和后端数据请求等)。

必须主动触发Nginx监听的端口才能实现Nginx代理
IP:PORT-IP定位Nginx所在容器,PORT触发Nginx监听代理。

IP:定位容器
PORT:触发Nginx监听端口

在这里插入图片描述
前端运行环境区别
本地都是编译打包跑在Node上,容器是npm run build编译打包资源放到内存由Nginx代理Url请求前端静态资源。
前端容器只跑了一个NG,其余的是静态资源存储在内存中。
前端工程先npm install下载package.json中依赖和命令脚本(npm start等命令)为node_modules再将其中的依赖和页面等npm run build(webpack)打包为资源文件夹.
npm run build=dist包=node_modules依赖+src,config等工程文件=打包为一个一个资源文件包(可通过analyze查看每个包的原始路径就能看到有的根路径是node_modules有的是src)

Nginx并不负责编译运行代码只负责代理转发url请求原生代码页面资源,最终浏览器编译运行原生代码页面,出错会在浏览器控制台console报出来。
浏览器运行打包好的umi.js等资源文件实现路由映射等功能。

在这里插入图片描述

Nginx转发流程(监听端口和启动端口)
项目访问Nginx工程的IP:PORT/path才会实现路径/path/映射

IP是Nginx搭载的工程IP,PORT是Nginx监听端口。

映射路径的编写方法:
proxy_pass :末尾带/不拼location,不带/拼location
假设下面四种情况分别用 http://47.168.10.1:8001/proxy/test.html 进行访问
location /proxy/ {
proxy_pass http://127.0.0.1:8001/;
}
代理到URL:http://127.0.0.1:8001/test.html

location /proxy/ {
proxy_pass http://127.0.0.1:8001;
}
代理到URL:http://127.0.0.1:8001/proxy/test.html

location /proxy/ {
proxy_pass http://127.0.0.1:8001/aaa/;
}
代理到URL:http://127.0.0.1:8001/aaa/test.html

location /proxy/ {
proxy_pass http://127.0.0.1:8001/aaa;
}
代理到URL:http://127.0.0.1:8001/aaatest.html

———————————————— 版权声明:本文为CSDN博主「白小白的小白」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42874635/article/details/115702184

Nginx代理前端页面请求流程

前提:一个URL前端页面需要经过Nginx代理多次http资源文件请求。

Nginx不会直接代理前端页面的URL请求资源文件,可以查看NG配置文件中并无前端页面URL的直接代理。
前端URL页面的资源请求都走的Nginx对于/的代理。

前端Nginx起始先根据URL匹配/获取html框架页面(包含URL路由配置),浏览器解析html框架页面(URL路由配置)后再次匹配/获取页面资源。
先匹配/获取html框架页面解析路由后再匹配url具体页面资源。
在这里插入图片描述
这个 Nginx 配置指令主要用于指定静态文件的根目录和处理请求的方式。以下是对你提供的配置的详细解释:

root /usr/share/nginx/html;

location / {
    try_files $uri $uri/ /index.html;
}
  1. root /usr/share/nginx/html;:

    • 这个指令设置了 Nginx 用来提供文件的根目录。在这个例子中,根目录是 /usr/share/nginx/html
  2. location / { ... }:

    • 这个块定义了如何处理对根路径(/)的请求。
  3. try_files $uri $uri/ /index.html;:

    • 这个指令尝试按特定顺序提供文件:
      1. $uri:首先,尝试找到与请求 URI 完全匹配的文件。
      2. $uri/:如果找不到文件,尝试找到与请求 URI 匹配的目录。
      3. /index.html:如果既找不到文件也找不到目录,则回退到提供 index.html 文件。

总结来说,这个配置告诉 Nginx 从 /usr/share/nginx/html 目录中提供文件。当收到请求时,Nginx 首先查找与请求 URL匹配的文件。如果找不到文件,再查找与请求 URL 匹配的目录。如果仍然找不到,则最终提供 index.html 文件。这种配置常用于单页应用程序(SPA),以确保所有路由都由主 index.html 文件处理,从而让前端框架来处理路由。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值