深度剖析浏览器请求行为, 输入www.baidu.com 回车后,背后发生了什么?

深度剖析互联网请求发送到页面展示整个执行过程

概要

涉及技术:网络通信、HTTP协议、Web应用服务器、Web服务器、计算机系统原理、CDN

整体架构流程

在这里插入图片描述
                     浏览器首次发送请求到页面展示整个执行过程图

技术名词解释

下面对涉及到的相关技术做个简单解释,如有错误,欢迎各位交流指正。
涉及相关技术
DNS:

域名系统,采用UDP协议进行网络通信,充分利用了UDP的优势,并且使用缓存技术,对已经解析过程域名会进行缓存,优先从缓存中获取,如果缓存存在域名对应ip,直接返回,速度非常快,响应一般在微秒级,其中一个域名可对应多个ip地址,域名分级概念,比如https://www.baidu.com,整个域名就是www.baidu.com,其中com是顶级域名,baidu是一级域名,www是二级域名,依次类推,如果www前面还有值,就是三级域名。在申请建网站时,需要购买独立域名,一个域名下可以建立多个子域名。

TCP/UDP:

TCP:传输控制协议
特点:面向连接、可靠、基于字节流全双工通信协议。
1.面向连接:就是表明使用该协议进行通信前需要构建连接,也就是socket套接字连接。这里面涉及到三次握手,网上一大堆教程,不在此进行介绍,
2.可靠: 该协议提供丢包重传机制,发送方发生数据包给接收方时,接收方需发送ACK确认包给发送端,如果发生很长一段时间发送方未收到来自于接收方的ACK包,发送方误以为接收方没有接收会进行对数据包重传。
3.高效:使用滑动窗口机制,动态改变发送包的传输速率,提升网络吞吐量。
4.通信:在讲述之前,读者需明白网络四层/七层模型,以Http协议为例子,应用层将请求消息进行包装成Http消息结构,传输层使用TCP协议,补充了发送端【客户端】和接收端【服务端】的端口等信息组装成一个TCP网络数据包,网络层将TCP数据包继续包装成IP数据包,其中IP模块包包含了发送端和接收端的IP地址、MAC地址(网卡驱动运行的唯一的物理地址),最后将IP数据包封装成帧,帧补充了报头、帧序列校验(用于避免帧发送过程中出现被篡改的情况)、帧起始计算符(用以计算帧数据开始的位置)。然后CPU响应一个发送请求中断,调用网卡驱动程序,将数据复制到网卡缓冲区,将数据转化为正向变化的电压脉冲如果是有线连接的话,走以太网发送出去。其中网卡作用就是将二进制转为正向变化的电压脉冲信号。一般说128Mbit/s 指的就是单位时间内将128Mbit字节信息转为电压脉冲信号的能力。
5:字节流:数据传输过程中使用二进制字节数据。
6:全双工:发送端和接收端通信过程中可以同时进行发送和接收操作,对应的还有半双工通信、单工通信,半双工通信即发送端和接收端同一时刻只能发送或者接收。单工通信,就是消息只能从发送端到接收端,单向传输。
应用场景
数据下载,文件传输,浏览网站,远程登录,电子邮件,可靠性要求高的视频、音频流传输等

UDP

用户数据报协议 特点:高效、不可靠
1.高效:体现在无需建立连接,传输速度比TCP快。
2.不可靠:没有TCP丢包重传等可靠性机制 应用场景: 适用于发送数据对数据可靠性要求不高的数据量较小的数据传输。比如DNS系统,视频会议,实时通信等

Xhr/fetch:

网络请求不同方式: Xhr 全名,XMLHttpRequest,浏览器使用该方式请求,可以实现无刷新页面下更新页面数据,在AJAX变成中大量使用。
Xhr特点:
1.异步请求,不会阻塞当前线程
2.支持跨域请求
3.基于事件驱动,提供了注入onprogress、onload、onerror等方法动态监听请求的状态变化
4.扩展性,对请求头、方法完全控制,使用更加灵活
Fetch特点:
为了解决Xhr请求回调地狱等问题衍生出的新的网络请求API。
1. 天生Promise支持:Promise异步请求,可维护性更高
2. 方法简洁:使用更简单。
两者区别
1.Fetch请求默认不携带cookie,需要手动设置credentials属性,Xhr会自动携带
2.Fetch 不具备请求取消、请求进度监听机制
3.Fetch 对低版本浏览器兼容性不太好
4.对于responseType为json /blob等 Fetch 需要手动解析,对于出现错误的响应,Fetch只有在网络错误情况下才会reject Promise。其他一律被视为成功,增加了使用者解析工作量。

HTTP/HTTPS:

在介绍HTTP协议之前,先回顾下,HTTP协议下一层采用TCP协议进行传输,由于TCP协议会存在粘包现象(读者可自行百度),服务端为了更好地处理TCP连接某个具体的请求信息,HTTP协议采用消息标记(\r\n 回车换行和\r\n\r\n 空行)、ContentLength组合方式来解决这个问题。
HTTP协议结构
请求:
1.请求行 : 协议 版本 请求路径【\r\n】【消息标记】
2.请求头:各种头信息,太多了,参照网上【\r\n】【消息标记】
3.空行【\r\n\r\n】【消息标记】
4.请求体【可以为空,比如Get】
响应:
状态行: 状态码比如【2xx,表示成功】【4xx,客户端异常】【5xx,服务端异常】【1xx,请求处理情况】【3xx,需要进一步操作】
响应头 : 各种头信息参照网上
空行
响应体:各种格式通常是JSON.

这里着重讲述下各个协议中涉及缓存重要属性
讲述之前,先说下,客户端缓存分为浏览器缓存比如Local Storage、Session Storage、Cache storage 等和HTTP缓存。其中HTTP缓存分为强制缓存协商缓存
强制缓存表明在使用过程中,如果缓存尚未失效的情况下,浏览器将不在发送请求,直接使用强制缓存。
协商缓存,则每次都向服务端发送一次请求,如果缓存数据没有发生变更,则浏览器仍旧使用缓存数据,此时请求响应为304,否则将获取服务端的最新数据作为缓存,并添加至缓存中,请求响应为200。下面讲述下缓存在各个协议下的实现方式:
1.强制缓存
Cache-Contorl: no-store 表明禁用缓存,no-cache 表明使用最新数据,
max-age=600 【表示缓存10分钟】
Expires: Wed, 06 Nov 2024 10:19:05 GMT 表示过期时间,这个相对来说不准确。
其中Cache-Control是HTTP1.1使用,优先级更高,Expires是HTTP1.0使用。
2.协商缓存:
Etag: 一般是一个根据请求资源动态生成的序列号,一个截图示例。 在这里插入图片描述
Last-Modified: Mon, 06 Mar 2023 03:18:42 GMT 时间格式,记录上次修改的时间。
其中Etag是HTTP1.1使用,优先级更高,Last-Modified是HTTP1.0使用。

如果请求用到协商缓存,
如果是采用Etag,会发送一次带有IF-NONE-MATCH:Etag的值给服务端,服务端会根据Etag值是否一致来判别当前数据是否已经发生变更,无变更则让浏览器使用缓存,有变更则返回最新数据,并写入缓存中。
如果是采用Last-Modified,请求会携带IF-MODIFIED-SINCE=Last-Modified的时间,给服务端,根据时间来进行判断,如果时间小于服务端的修改时间,则需要重新获取最新数据。

CDN

内容分发网络:这个用来提升资源速度一个网络中心,这个本身是不存储数据,只是作为Web服务器(比如Nginx等)请求的一个缓冲机制,利用的是将请求物理地址靠近客户端,缩短请求距离来实现请求加速。这里有个边缘层、中心/区域层的概念,用户请求服务器资源时,如果配置了CDN加速,会优先从里用户相对最近的网络运营商下的一个服务进行请求,也就是CDN边缘层,如果此时CDN存在数据,则直接返回给客户端,如果没有CDN边缘层会向中心层发请求获取数据,如果有则返回,并加入边缘层缓存中,如果此时中心层也没有请求的数据,就会触发回源操作,CDN向Web服务器发请求获取数据,然后加入缓存中并发送给边缘层,边缘层将数据返回给客户端。 如果一个请求频繁触发回源操作,那么效率不升反将。这个需要CDN工程师做好代码优化编程。

Web服务器以Nginx为例

Web服务器有很多种,目前最主流的就是Nginx和Apache两种。这里以Nginx为例,简单介绍下,Nginx作为Web服务,可以实现静态资源缓存、反向代理【这个可以解决跨域请求问题】、负载均衡【将请求节点均衡落在集群的各个节点上,提升服务端性能】等功能,某些情况下还可以利用Nginx动态获取服务端请求资源。这里只做个简单介绍。

Web应用服务器以Tomcat为例

Tomcat使用java开发,很多情况下作为JAVA项目首先应用服务器,相对功能较多,这里简要介绍下Tomcat几种部署方式以及Tomcat执行请求的流程。

1.部署方式:
(1)Webapps目录下部署项目War包
(2)Server.xml 文件Host标签下配置Context 补充<Context docBase="" path="" >
(3)在Conf/Catalina/localhost/ 新增配置xxx.xml 文件,并配置Context。其中一个Context就是一个单独的应用。

2.Tomcat 执行请求流程:

在这里插入图片描述
Tomcat8为例子,默认并发线程数为200,nio线程默认是10。当然你可以优化线程池配置,手动配置线程池需要补充<Executor>标签,如果没有配置线程池,走默认设置。

Connector作为连接器,主要用来将请求转发给服务容器
Engine:引擎容器
Host:虚拟主机 Context:
容器 Wrapper:Servlet的包装,其中一个Servlet就是一个Wrapper,管理Servlet生命周期,最底层容器

这个执行流程频繁使用到反射技术,首先是套接字处理方法SocketProcess(),接受请求,请求解析,拿到HttpServletRequest.
connector连接器获取Engine容器 然后调StandardEngineValue.invoke()
Engine容器继续获取Host容器 调用StandardHostValue.invoke() Host容器继续获取Context容器
调用StandardContextValue.invoke() Context容器获取Wrapper容器
request.getWrapper()。 Wrapper容器获取DispatchServlet 。这个时候就已经来到中央控制器了。
DispatchServlet.doDispatch 处理请求。这个时候就触发SpringMVC流程了。

JS

JS全名Javascript,是一门弱类型语言,主要用以前端界面开发,随着Node.js 编程快速兴起,如今也可开发后台,可作为全栈web开发语言。这个语言和java本身没有什么关系,大体分为三部分:ECMAScript、DOM、BOM。 ECMAScript 是js 开发的一个语法标准,js可通过操作DOM来实现界面各种行为展示,BOM是浏览器自带的一些操作对象。比如LocalStorage/SetInterval 是属于Window对象。
现在一般采用渐进式框架来取代JS,比如Vue./React 等,一个是提升开发效率,一个是提升运行效率,传统原生js对DOM操作会导致页面重排、重绘,性能拉胯,于是就有了采用VDom操作替代Dom操作,减少重排次数发生,提升页面渲染性能。这里只是做个简单介绍。

技术细节

提示:这里可以添加技术细节

  • 集群:多个服务节点一起部署,用以提升整个系统QPS/TPS,以及保持系统高可用,避免单节点宕机,整个系统陷入瘫痪的情况。
  • Web应用服务器:高并发场景下,这个也是集群,一台机器通常扛不住大量的流量请求,为了应对更为复杂的场景,通常是使用多级缓存来架构,从CDN到Nginx集群【Nginx也可以缓存数据】,到Tomcat集群,服务器内部使用非关系库如redis缓存负责请求响应,redis也可部署为一个集群,最后在JVM内部还可以使用本地缓存方式来进一步降低对关系数据库的请求。本地缓存通常选择性能较高的Caffeine组件。
    渲染页面细节:
    浏览器从下载数据到解析Html、加载Cssom、加载执行js计算布局,分层分块光栅化,图形绘制,图形合成,GPU渲染最后得到一张完成的页面

1.解析Html: 获取html文件解析里面各种Html标签得到无样式的纯标签结构,这里通常要提升解析速度,对js采用异步加载方式,即<script async></script>要带有async标识, 避免js加载阻塞解析Html。
2.加载Cssom: 下载css文件解析为Cssom 结构,两者合成为可见Dom树。
3.执行js:js加载执行有可能存在操作DOM,这个过程会计算样式、元素布局,此时得到的就是带有位置信息的DOM树。
4.分层分块光栅化:分层是因为页面是由多个层图构建的,页面元素具有层级概念,因此需要对不同层级的元素分成若干块进行绘制图,这个绘制图本质就是在页面位置上写入不同像素点,这个光栅化就是写入像素点操作,这个交由光栅化线程池完成。分块交由合成线程完成。分层是js主线程完成。
5.合成并展示:合成交由合成线程完成不同位置块进行合并,展示就是GPU根据像素点绘图。

额外补充:

浏览器默认并发线程是有数目限制的,谷歌默认是6,就是说,对于同一个域名请求,同时只能发送6个请求,这个是HTTP2(不包含HTTP2)以前实现机制,但是HTTP2优化了这块,允许一次TCP连接可同时发送多次HTTP请求,IO多路复用。
因此基于以前对于静态资源访问优化,可通过多域名来实现,HTTP2以后这个效果并没有太大作用,相反还额外带来DNS域名、额外请求连接代价开销

巧用prefetch dns-prefetch preload 属性,可实现性能提升。

prefetch 默认将下一次可能访问的数据提前获取并加入缓存中,下次请求不用发送请求,走缓存。
preload预加载,可提前实现加载一般用于<link rel='stylesheet' preload >
前端编码规范,html结构优先、其次css,最后放js脚本。

小结

本次分享了浏览器请求服务运行的可能大致流程,由于各个公司系统架构存在差异,因
此这个流程仅仅作为参考学习所用,书写中如存在错误,还望各位多多包涵。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值