一,总体来说分为以下几个步骤:

  1. DNS解析
  2. TCP连接
  3. 发送HTTP请求
  4. 服务端处理并返回HTTP报文
  5. 浏览器解析渲染
  6. 连接结束

其实在DNS解析之前还有一个就是解析URL,URL称为统一资源定位符,俗称网址,URL的组成部分为:

  • 传输协议
  • 服务器
  • 域名
  • 端口
  • 虚拟目录
  • 文件名
  • 参数

连接起来就是:http://www.baidu.com:80/html/index.html?name=bob&id=102#page,80端口是默认端口一般不显示出来。

  1. DNS解析

对于DNS解析就是确定你需要的资源在哪台机器上的一个过程,当你在浏览器输入一个地址(www.baidu.com),其实这不是百度的真正地址,这是一个域名,我们需要的是IP地址(180.149.132.151),互联网每一台计算机都有一个唯一的IP地址,因为IP地址不方便记忆所以才有了域名方便记忆,互联网设计者需要在方便性与可用性方面之间做出一个权衡,这个权衡就是域名转换为IP地址,这个过程称作NDS解析,它充当的是一个翻译的角色,那么它是怎么翻译的?

上图就是查找IP地址的过程,首先在本地域名服务器中查找IP地址,如果没有找到本地域名服务器会向根域名服务器发送一个请求,根域名服务器默认是“.”,其实真正的域名是www.google.com.,但是所有域名都一样有点,所以可以省略,浏览器在请求的时候会自动加上。如果根域名服务器没有该域名,本地域名向com顶级域名发送一个请求,没找到,然后依次下去,直到最后本地域名服务器得到百度的IP地址然后把他还存在本地,供下次使用,从上述过程发现域名解析其实是一个从右到左的过程:. -> .com -> google.com. -> www.google.com. 。了解了上述DNS解析过程,我们可以做一些事:

DNS优化

上图中DNS解析经历了8个过程,这些过程中存在UDP和TCP请求,为什么两种请求,自行度娘一下,如果每次的经历这么多的步骤,那么太耗时了,如何解决呢?就是DNS缓存。

$ DNS缓存

DNS缓存有多级,从离浏览器距离排序,有:浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。

  • 在你的chrome浏览器中输入,chrome://net-internals/#dns 就可以看到浏览器的DNS缓存。
  • 系统缓存主要存在/etc/hosts(Linux系统)中,macOS,或者windows自行百度查阅。
  • 其他缓存也自行百度查阅。(作者懒得写了😂)

$ DNS负载均衡

如果DNS每次请求返回的地址都一样,那么咱们认为我们需要的资源在一台服务器上,如果你的网址流量比较大,那么就需要更高的服务器性能和带宽,其实大型网址他们都有好多台服务器,从用户的角度看,不管你有多少台,我只关注的是处理我的请求,这样DNS可以返回一个合适的服务器IP地址,至于返回哪一台服务器IP根据当前服务器的负载数量,服务器离用户的距离和用户的地理位置等决定,这个过程就是DNS负载均衡,又叫做DNS重定向,我们平时用的CDN就是利用DNS的重定向技术,DNS返回一个和用户距离近的IP地址,CDN节点服务器负责响应用户的请求,提供需要的内容。类似的CDN有,75CDN,AWS的Amazon CloudFront好像就是自己配置cloudFront来加快网站的访问速度,具体小编没有仔细研究,可以点击连接查看。

2. TCP连接

在开始TCP连接之前我们了解一下互联网的连接模型--层,(不知道放在这里讲合不合适)

互联网分为好几层,每一层都有自己的功能,并且每一层需要下一层的支持,我们用户平时接触到就是应用层,(分的层数没有一个标准,有分四层,有分7层,在这里分为5层)。

  1. 实体层:主要是电脑的连接,用电缆将电脑之间连起来,负责传送0和1的电信号。
  2. 链路层:主要确定数据的分组,0和1的分组方式等。
  3. 网络层:引进新的地址,区分不同的计算机是否在同一个子网络。
  4. 传输层:建立端口到端口之间的通讯。
  5. 应用层:规定应用的数据格式。
    具体每一层的数据包,协议等可以查看下面给出的链接
    TCP/IP模型的一个简单解释
    互联网协议入门(一)
    互联网协议入门(二)
    HTTP协议入门
    图解SSL/TLS协议

$ HTTP协议

http作为互联网常见的协议,http协议是应用层,使用TCP为其传输层协议作为基础,当TCP出现性能瓶颈,也会影响上层的http传输,

如上图最底下的协议是IP协议,属于网络层,它主要连接两台主机,并实现通信,IP协议虽然能把数据报发送到目的主机,但是并没有交付给具体的应用程序,端到端的通信才是应用程序之间的通信。这就需要上层的UDP/TCP,来确定通信。

UDP:在传输数据前不需要先建立连接,省去了许多的连接的步骤,速度比较快,但是也带来一些问题,传输可能不会成功,并且服务端收到报文后不会给出任何确认信息,这就带来了很多的不确定性,其对应的上层的协议有:DNS,NFS, TFTP等等。

TCP:在传输数据之前必须先建立连接确认,数据传输完成之后要释放连接,TCP是一种可靠的运输服务,传输可靠安全,对应的上层协议有:HTTP,SMTP,FTP等。

http,依靠的是TCP协议,所以首先的TCP建立连接,TCP连接——三次握手四次挥手,具体的连接方式查看链接,TCP的三次握手与四次挥手(详解+动图)

$ HTTPS协议

HTTPS其实就是HTTP的一个升级版本(传输数据更加的安全),加入了一个SSL(or TLS)协议

http报文是包裹在TCP报文中发送的,服务器端收到TCP报文会解包提取出HTTP报文,但是在这个过程中存在一定的风险,HTTP的报文是明文的,有可能被截取的话会存在一定的泄露风险,那么如果在http进入TCP之前通过做一次加密就可以解决这个问题,所以就有了HTTPS,通过SSL或者TLS使用非对称加密,对称加密以及hash等算法,具体请参考阮一峰老师一些文章。

1. 《HTTPS 协议概述》
2. 《图解 HTTPS 协议》
3. 《HTTPS 协议的七个误解》
4. 《HTTPS 协议的延迟有多大?》
5. HTTPS 升级指南

3. 发送HTTP请求

发送HTTP请求主要从客户端发出,前端工程师主要接触的就是客户端,所以对于这一部分我会尽量写的详细一些,发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议中发送到服务端指定的端口(http协议80/8080端口,https协议443端口),HTTP请求报文主要由三部分组成:请求行,请求报头,请求正文。

$. 请求行

格式为:Method RequestURL HTTP-version

如:GET index.html HTTP/1.1

常见的method有:GET, POST, PUT, DELETE, OPTIONS, HEAD。

  • GET与POST的区别?
    当在面试中被问到的时候,我们或者会很轻松的给出下面的答案,
    a. GET将参数包含在URL中,POST将参数放在request body中,
    b. GET在浏览器中回退是无害的,但是POST会再次提交数据。
    c. GET的URL会在地址会记录在bookmark中,post不可以。
    d. GET会被浏览器缓存,但是POST不会,除非手动设置。
    e. GET的请求URL的长度会被限制,一般为2k,POST没有。
    f. GET不适合传输一些敏感类的信息,因为参数直接暴露在URL中,POST可以用来传送。
    当你信心满满的说完这些答案的时候,面试官感觉还是不满意,问你还有没有,其实如果我们对互联网数据传输有点研究的话可能知道,其实GET与POST本质上没有区别,他们都是HTTP协议的两种发送数据的不同方式,而HTTP的底层依靠的还是TCP/IP,所以GET/POST底层还是TCP/IP,其实我们也可以给GET的request body中放入数据,但是有的服务器不会解析GET request body中的数据,你也可以在POST中的URL中放入参数,这样他们为什么还是不一样呢,由于HTTP的一些规定和浏览器的限制导致在传输方式上的不同。
          说了这儿么多好像我还没有说出面试官想要你回答的答案,其实是GET和POST的重大区别是,GET产生一个TCP数据包,POST产生两个数据包,对于GET请求,浏览器会把header与data一起发送出去,服务端响应200的状态码,但是POST首先会发送一个header,服务端响应100 continue,然后在发送data到服务端,所以产生两个数据包,并不是所有的浏览器都发送两次数据包,例如,Firefox只发送一次。

$. 请求报头

请求报头允许客户端向服务器传递请求的附加信息和客户端的自身的一些信息。常见的报头包括以下:Accept, Accept-charset, Accept-Encoding, Accept-language, Content-Type, Authorization, Cookie, User-Agent等。

从上图中看出,应用了Accept, Accept-Encoding, Accept-language, Connection, Cookie, User-Agent等字段,Accept指定客户端接受哪些类型的信息,Accept-Encoding指定接受的编码方式,Connection: Keep-alive告诉客户端本次请求之后不需要关闭TCP连接,这样可以为下次请求节省TCP的连接时间。

$  请求正文

当使用POST或者PUT的请求方式时,需要从客户端发送一些数据到服务端,这些数据存储在请求正文中,在请求包头中有一些与请求正文相关的信息,如现在采用的Rest架构的网站,常采用json的数据格式,这时候需要设置Content-Type: application/json。

4.  服务端处理并返回HTTP报文

前端发送到后端固定的端口下,后端从固定的端口下接收TCP报文开始,这部分对应编程语言中的socket,它对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP request对象,供上层使用,这一部分由web服务器去处理,常见的web服务器有,Nginx, tomcat, node等等。

HTTP响应报文由三部分组成:状态码,响应报头,响应报文。

$  状态码

服务端返回的状态码,用于确认服务端对请求的处理结果的状态,状态码由三位数字组成,第一个数字定义了响应的类型,有5中常见的取值:

  1. 1XX: 表示服务端已经接收信息,正在进行处理
  2. 2XX: 成功,请求已经被成功接收,理解,接受。
    200:成功,返回正常的处理结果。
    204:请求成功,但是没有数据,浏览器不用重新刷新,也不用导向新的页面。
  3. 3XX:一般代表重定向,要完成操作需要进一步的操作。
    301:资源被永久的重定向到其他的URL上。
    302/307:临时重定向,请求的文档已被移到其他的地方,此文档的新的URL在location响应头里。
    304:未修改,客户端缓存的版本是最新的,客户机应该继续使用它。
  4. 4XX:客户端错误,请求有语法错误或者请求无法实现。
    400:客户端访问的页面域名不存在,或者请求错误。
    401:请求要求用户的身份认证。
    403:禁止,服务端理解客户端的请求,但是拒绝处理,通常用于服务器上文件或目录的权限设置。
    404:找不到,服务器不存在客户端请求的资源。
    422:请求格式正确,但是由于含有语义错误,无法响应。
  5. 5XX:服务器端错误,服务器内部处理错误。
    500:服务端发生错误。
    501:服务器不支持请求功能,无法完成请求。
    502:充当网关或者代理的服务器,从远端服务器上接收到一个无效的请求。

$ 响应报头

响应报头的字段有很多,Cache-Control, Connection, Server, Content-Length等等。

$ 响应报文

服务端给客户端返回一些相应的文本信息,例如web服务端给浏览器返回html, css ,js ,图片等文本信息。

5.  浏览器解析渲染页面

浏览器收到响应报文后,会通过解析渲染,最后将页面展现在屏幕上,每个浏览器都有他们的渲染引擎,因为厂商不一样,他们的采用渲染引擎也不一样,例如:chrome,safari采用的是webkit内核,Firefox采用Geoko内核,360/IE浏览器采用Trident内核。尽管他们的渲染引擎不一样,但是渲染的逻辑也大同小异。

解析HTML以构建DOM树 -> 构建render树 -> 布局render树 -> 绘制render树

首先浏览器解析HTML然后构建DOM树,DOM树的构建是一个深度遍历的过程,只有当前节点的子节点都够建好之后才会去构建当前节点的兄弟节点。然后接着解析CSS,构建css样式规则,然后通过attachment之后构成CSS渲染树,有了上述两个树之后开始构建render Tree,此时的render Tree对于像一些设置display:none;的节点就不构建,有了render Tree树之后,浏览器知道网页中有多少节点,并且知道每个节点的CSS样式以及他们的所属关系,从而去计算他们在页面上出现的位置。按照计算出来的规则,通过显卡,将内容绘制在屏幕上。这个过程中涉及到两个知识点,reflow(回流),repaint(重绘),他们在页面首次渲染的时候都有,DOM节点中各个元素都以盒模型的形式存在,这些都需要浏览器去计算和其位置和大小,这就是reflow,当页面中的节点的位置或者大小发生变化时,都会引起reflow,例如折叠菜单,展开都会引起reflow。repaint,当布局确定后开始确定节点的样式,颜色,边框等,这就是repaint,对于display:none, 和visibility:hidden,前者会产生reflow, 后者产生repaint,reflow和repaint在很消耗性能,可能会造成页面卡顿,我们因尽量减少reflow和repaint。

  1. 如何减少回流与重绘?(点击链接在文章最后)

HTML,CSS解析完成到js解析,js解析由浏览器自身的解析引擎完成,JavaScript的最大特性就是单线程,为什么呢?因为JavaScript主要用途就是与用户互动,操作DOM,假如是多线程,当我们在一个线程中为该节点添加内容,但是另一个线程却删除该节点,那么浏览器以哪个线程为基准?或者你听过HTML5中的web worker,允许js创建多个线程,但是规定子线程不可以操作DOM,这没有改变js单线程的本质。

上图就是js引擎渲染图,js在同一时间内只能做一件事情,所有的任务都要排队,前一个任务结束才能开始下一个,如果存在比较耗时任务那么就可能等很长时间,所以为了让后面的任务先执行,所以就有了同步任务和异步任务,js的执行机制可以看作一个主线程加上一个任务队列,同步的任务放在主线程上执行,异步任务放在队列中执行,所有的同步任务在主线程执行形成一个执行栈,异步任务有了运行结果会在任务队列中放一个事件,脚本先运行执行栈中的任务,然后再从异步的队列中提取事件,执行异步任务,这个过程不断的重复,就叫做,事件循环(event loop)。

对于事件循环写的估计不详细,不太完美,你可以参考阮一峰大大的博客文章,JavaScript 运行机制详解:再谈Event Loop

浏览器解析过程中如果遇到请求外部资源,如图像,css等,浏览器会去下载该资源,这个过程是异步的,不会影响HTML文档的解析加载,但是当解析加载过程中遇到js文件时,HTML文档会挂起,需要等待js文档加载执行完毕后,HTML文档才能继续,因为js可能会修改DOM,如创建添加DOM等,所以在js执行完之前后续的HTML不能继续,这就导致页面被阻塞,所以推荐将JS文件放在HTML文档的底部,对于CSS加载不影响js的加载,但是会影响js的执行,这就需要保证js执行前css已经全部加载,所以加载的css放在HTML文档的顶部。

优化

了解浏览器的请求过程与解析等,让我们在web优化方面有了思路,网上有很多的优化思路如,雅虎的34条军规,其他的如,合理的设置缓存,使用DNS加快资源的加载,对响应的内容如,图片压缩等,配置负载均衡,加快资源的加载,对于浏览器端由于reflow会很耗时间,尽量避免多次回流。

总结,写文章之前参考了好多的大佬的文章,在这里要感谢大佬,感谢阮一峰老师的博客,另外找了一些面试题目,文中给出了部分面试中可能被问的题目和答案,其他没有写答案的点击链接就可以查看相应的文章,文章中可能存在一些打字错误或者理解错误,大家可以在评论框留言指出,我会认真查看大家的留言。

--本文章已同步到微信公众平台,扫描下方二维码关注可快速阅读:--
打赏
X

感谢大佬的打赏😘