阅读 695

大前端面试必问--从输入 URL 到页面展现中间发生了这些!(最全面拓展讲解)

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

这个问题真的是个老生常谈的问题,作为一个前端或者后端都应该熟记于心,这个过程可以说的很粗糙,也可以详谈,其中展现了许多网络相关的知识点,于是必须要好好整理下

主要总体来说分为以下几个过程

  • URL输入

  • DNS解析

  • TCP连接(三次握手)连接复用

  • 发送HTTP请求(请求的四部分)

  • 服务器送 HTTP 响应

  • 关闭 TCP 连接(四次挥手)

  • 浏览器解析渲染页面

1. URL输入

首先我们是在浏览器中输入URL,URL中文名叫做统一资源定位符,统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

主要组成部分:protocol (协议): // hostname(主机名)[:port] (端口) / path(路径) / [;parameters] (参数)
这里我们要注意的时候浏览器遵循的同源策略,我们前端访问接口的时候通常会遇到跨域的问题,这里所有的域是协议、域名和端口号的合集,同域就是所协议、域名和端口号均相同,任何一个不同都是跨域
关于跨域与解决跨域的方法可以参考下文;

2. DNS解析

DNS解析的过程就是寻找哪台机器上有你需要资源的过程。当你在浏览器中输入一个地址时,例如www.google.com,其实不是google网站真正意义上的地址。互联网上每一台计算机的唯一标识是它的IP地址,但是IP地址并不方便记忆。用户更喜欢用方便记忆的网址去寻找互联网上的其它计算机,也就是上面提到的百度的网址。所以互联网设计者需要在用户的方便性与可用性方面做一个权衡,这个权衡就是一个网址到IP地址的转换,这个过程就是DNS解析。它实际上充当了一个翻译的角色,实现了网址到IP地址的转换。网址到IP地址转换的过程是如何进行的?

2.1DNS解析的过程

DNS查找顺序:
浏览器缓存–> 操作系统缓存–> 本地host文件 --> 路由器缓存–> ISP DNS缓存 --> 顶级DNS服务器/根DNS服务器
分析查找www.google.com的IP地址过程,: . -> .com -> google.com. -> www.google.com.
有人会很奇怪怎么会多一个点,并不是我多打了一个.,这个.对应的就是根域名服务器,默认情况下所有的网址的最后一位都是.,既然是默认情况下,为了方便用户,通常都会省略,浏览器在请求DNS的时候会自动加上,所有网址真正的解析过程为: . -> .com -> google.com. -> www.google.com.。

2.2 DNS查询的两种方式:递归查询和迭代查询

  1. 递归解析
    ​ 当局部DNS服务器自己不能回答客户机的DNS查询时,它就需要向其他DNS服务器进行查询。此时有两种方式,如图所示的是递归方式。局部DNS服务器自己负责向其他DNS服务器进行查询,一般是先向该域名的根域服务器查询,再由根域名服务器一级级向下查询。最后得到的查询结果返回给局部DNS服务器,再由局部DNS服务器返回给客户端。

  2. 迭代解析
    当局部DNS服务器自己不能回答客户机的DNS查询时,也可以通过迭代查询的方式进行解析,如图所示。局部DNS服务器不是自己向其他DNS服务器进行查询,而是把能解析该域名的其他DNS服务器的IP地址返回给客户端DNS程序,客户端DNS程序再继续向这些DNS服务器进行查询,直到得到查询结果为止。也就是说,迭代解析只是帮你找到相关的服务器而已,而不会帮你去查。比如说:baidu.com的服务器ip地址在192.168.4.5这里,你自己去查吧,本人比较忙,只能帮你到这里了。

2.3 DNS负载均衡

当一个网站有足够多的用户的时候,假如每次请求的资源都位于同一台机器上面,那么这台机器随时可能会蹦掉。处理办法就是用DNS负载均衡技术,它的原理是在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的机器上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等。

2.4 DNS缓存

了增加访问效率,计算机有域名缓存机制,当访问过某个网站并得到其IP后,会将其域名和IP缓存下来,下一次访问的时候,就不需要再请求域名服务器获取IP,直接使用缓存中的IP,提高了响应的速度。当然缓存是有有效时间的,当过了有效时间后,再次请求网站,还是需要先请求域名解析。

但是域名缓存机制也可能会带来麻烦。例如IP已变化了,仍然使用缓存中的IP来访问,将会访问失败。再如 同一个域名在内网和外网访问时所对应的IP是不同的,如在外网访问时通过外网IP映射到内网的IP。同一台电脑在外网环境下访问了此域名,再换到内网来访问此域名,在DNS缓存的作用下,也会去访问外网的IP,导致访问失败。根据情况,可以手动清除DNS缓存或者禁止DNS缓存机制。
在你的chrome浏览器中输入:chrome://dns/,你可以看到chrome浏览器的DNS缓存。系统缓存主要存在/etc/hosts(Linux系统)中

3. TCP连接(三次握手)

在通过第一步的DNS域名解析后,获取到了服务器的IP地址,在获取到IP地址后,便会开始建立一次连接,这是由TCP协议完成的,主要通过三次握手进行连接。

  1. 先Client端发送连接、请求报文:客户端向服务端发送一个syn的数据包这个时候客户端处于一个SYN_SENT的状态,等待服务器确认.
  2. 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  3. 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),并分配资源,此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手 这样TCP连接就建立了

4. 发送HTTP请求

建立了TCP连接之后,发起一个http请求。一个典型的 http request header 一般需要包括请求的方法,例如 GET或者 POST等,不常用的还有 PUTDELETE、HEADOPTION以及 TRACE 方法
.用报文的形式告诉服务器我们需要什么东西,完整的HTTP请求包含请求起始行、请求头部、请求主体三部分。

补充 (1)GET 对比 POST

参考答案: w3school: GET 对比 POST

其实看看其他请求方法的名字就能大概知道在什么时候用什么方法,这就很好的体现了语义化
先下结论,GET 和 POST 方法没有实质区别,只是报文格式不同。
GET 和 POST 只是 HTTP 协议中两种请求方式,而 HTTP 协议是基于 TCP/IP 的应用层协议,无论 GET 还是 POST,用的都是同一个传输层协议,所以在传输上,没有区别。
报文格式上,不带参数时,最大区别就是第一行方法名不同.不带参数时他们的区别就仅仅是报文的前几个字符不同而已
POST 方法请求报文第一行是这样的 POST /uri HTTP/1.1 \r\n
GET 方法请求报文第一行是这样的 GET /uri HTTP/1.1 \r\n
带参数时报文的区别:
在约定中,GET 方法的参数应该放在 url 中,POST 方法参数应该放在 body 中
举个例子,如果参数是 name=qiming.c, age=22。
GET 方法简约版报文是这样的

GET /index.php?name=qiming.c&age=22 HTTP/1.1
Host: localhost

复制代码

POST 方法简约版报文是这样的

POST /index.php HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded

name=qiming.c&age=22


复制代码

总结下

  • GET - 从指定的资源请求数据。是无副作用的,是幂等的,且可缓存
  • POST - 用于向指定的资源提交要被处理的数据,有副作用,非幂等,不可缓存
  • 参数。GET 的参数放在 url 的查询参数里,POST 的参数(数据)放在请求消息体里。
  • 安全。GET 相对 POST 安全(只是相对安全)
  • GET的URL会有长度上的限制, POST可以传输很多数据,GET 的参数(url查询参数)有长度限制,一般是 1024 个字符。POST 的参数(数据)没有长度限制(也是有4~10Mb 限制)
  • GET 用来读数据,POST 用来写数据,POST 不幂等(幂等的意思就是不管发多少次请求,结果都一样。)

补充(2) HTTPS和HTTP的区别

可以参考详细解析 HTTP 与 HTTPS 的区别
主要区别有以下几点

  1. https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

  4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

5.服务器返回一个 HTTP 响应

服务器在收到浏览器发送的HTTP请求之后,会将收到的HTTP报文封装成HTTP的Request对象,并通过不同的Web服务器进行处理,处理完的结果以HTTP的Response对象返回,主要包括状态码,响应头,响应正文三个部分。

补充:常见状态码

一般大家都知道404页面不存在,500服务器错误,301重定向,302临时重定向,200ok,401未授权啥的。

重点介绍三个状态码及相关的知识,他们分别是304协商缓存,101协议升级,以及307hsts跳转。

  • 304协商缓存
    先从304协商缓存开始吧。这是比较基础的知识。相信我,只要你提起304协商缓存,面试官一定会忍不住问你,什么是协商缓存?
    “协商缓存与强制缓存的区别在于强制缓存不需要访问浏览器,返回结果是200”.强制缓存不需要访问服务器,直接从浏览器中获取,此时是200。协商缓存,需要访问服务器,如果命中,会修改浏览器中的缓存头部信息,最后还是从浏览器中获取信息,此时是304,如果没有命中,则从服务器获取信息,此时是200,这时就到了你展示一下自己丰富的浏览器缓存知识的时候了。我一般会这么答:浏览器缓存分为强制缓存和协商缓存,优先读取强制缓存。强制缓存分为expires和cache-control,而expires是一个特定的时间,是比较旧的标准和cache-control通常是一个具体的时间长度,比较新,优先级也比较高。而协商缓存包括etag和last-modified,last-modified的设置标准是资源的上次修改时间,而etag是为了应对资源修改时间可能很频繁的情况出现的,是基于资源的内容计算出来的值,因此优先级也较高。协商缓存与强制缓存的区别在于强制缓存不需要访问浏览器,返回结果是200,协商缓存需要访问服务器,返回结果是304。

  • 101协议升级
    主要用于websocket,也可以用于http2的升级。websocket的特点和功效不细说,大家都很熟了。
    http2好处多多,一般说出支持单个连接多次请求,二进制,压缩头部,服务器推送等特征面试官就比较满足了。具体了解也是自行谷歌百度,这里也是不细说。当然这时候我们可能要应对一下面试官接下来的追问:到底https,http,http2以及它的原形spdy有什么区别,又分别有什么优点和不足,他们的建立连接分别又有着什么环节,这些知识就需要读者自己去充分搜索查询了。

  • 307 hsts跳转
    这个比较高端,原本的用法是用于让post请求的跳转去新的post请求,但也用于hsts跳转。hsts全称HTTP严格传输安全(HTTP Strict Transport Security,縮寫:HSTS),功能是要求浏览器下次访问该站点时使用https来访问,而不再需要先是http再转https。这样可以避免ssl剥离攻击,即攻击者在用户使用http访问的过程中进行攻击,对服务器冒充自己是用户,在攻击者和服务器中使用https访问,在用户和服务器中使用http访问。具体使用方法是在服务器响应头中添加 Strict-Transport-Security,可以设置 max-age,当然,提到了ssl剥离攻击,你一定很感兴趣还有什么方法可以对号称安全的https进行攻击呢?我这里了解到的有ssl劫持攻击,大概就是信任第三方的安全证书,这点被利用于代理软件监听https。如果还有更多的,欢迎补充。

仅仅三个状态码,都可以牵涉到如此丰富的知识,对于状态码,我们不能只是片面的去背诵状态码及对应的含义,要去主动挖掘,深入,借助http状态码来建立自己的网络体系。

平时常见的状态码::200, 204, 301, 302, 303,304, 400, 401, 403, 404, 500,503(一定要记住)

  • 200 OK 表示客户端请求成功
  • 204 No Content 成功,但不返回任何实体的主体部分
  • 301 Moved Permanently 永久性重定向,响应报文的Location首部应该有该资源的新URL
  • 302 Found 临时性重定向,响应报文的Location首部给出的URL用来临时定位资源
  • 303 See Other 请求的资源存在着另一个URI,客户端应使用GET方法定向获取请求的资源
  • 304 Not Modified 服务器内容没有更新,可以直接读取浏览器缓存
  • 400 Bad Request 表示客户端请求有语法错误,不能被服务器所理解
  • 401 Unauthonzed 表示请求未经授权,该状态代码必须与 WWW-Authenticate 报头域一起使用
  • 403 Forbidden 表示服务器收到请求,但是拒绝提供服务,通常会在响应正文中给出不提供服务的原因
  • 404 Not Found 请求的资源不存在,例如,输入了错误的URL
  • 500 Internel Server Error 表示服务器发生不可预期的错误,导致无法完成客户端的请求
  • 503 Service Unavailable 表示服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常

6. 关闭 TCP 连接(四次挥手)

  1. Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭(Socket),可以继续发送数据。

  2. server发送ACK,“告 诉Client端,你的请求我收到了,但是我还没准备好,请继续等我的消息”。wait:这个时候Client端就进入FIN_ WAIT状态,继续等待Server端的FIN报文。

  3. 当Server端确定数据己发送完成,则向Client端发送FIN报文,“告诉
    Client端,好了,我这边数据发完了,准备好关闭连接了”。

  4. Client端收到FIN报文后,“就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_ _WAIT状态,如果Server端没有收到ACK则可以重传。“Server端收到ACK后"就知道可以断开连接了”。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端 也可以关闭连接了。Ok,TCP连接就这样关闭了!

7. 浏览器解析渲染页面

浏览器在收到HTML,CSS,JS文件后

  • 解析 HTML
  • 下载 CSS(缓存
  • 解析 CSS
  • 下载 JS(缓存
  • 解析 JS
  • 下载图片
  • 解析图片
  • 渲染 DOM 树
  • 渲染样式树
  • 执行 JS

具体(以webkit为例)
通过HTML解析器解析HTML文档,构建一个DOM Tree,同时通过CSS解析器解析HTML中存在的CSS,构建Style Rules,两者结合形成一个Attachment。
通过Attachment构造出一个呈现树(Render Tree)
Render Tree构建完毕,进入到布局阶段(layout/reflow),将会为每个阶段分配一个应出现在屏幕上的确切坐标。
最后将全部的节点遍历绘制出来后,一个页面就展现出来了。

这个过程比较复杂,涉及到两个概念: reflow(回流)和repain(重绘)。下文会讲

当文档加载过程中遇到js文件,html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。因为JS有可能会修改DOM,最为经典的document.write,这意味着,在JS执行完成前,后续所有资源的下载可能是没有必要的,这是js阻塞后续资源下载的根本原因。

​ JS的解析是由浏览器中的JS解析引擎完成的。JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始。但是又存在某些任务比较耗时,如IO读写等,所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)。

​ JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。

补充 回流与重绘

DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。

Reflow,也称作Layout,中文叫回流,一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树,这个过程称为Reflow。
Repaint,中文重绘,意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就OK了,这个过程称为Repaint。
所以说Reflow的成本比Repaint的成本高得多的多。DOM树里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。
下面这些动作有很大可能会是成本比较高的
1、增加、删除、修改DOM结点时,会导致Reflow或Repaint。
2、移动DOM的位置,或是搞个动画的时候。
3、内容发生变化。
4、修改CSS样式的时候。
5、Resize窗口的时候(移动端没有这个问题),或是滚动的时候。
6、修改网页的默认字体时。

基本上来说,reflow有如下的几个原因:
1、Initial,网页初始化的时候。
2、Incremental,一些js在操作DOM树时。
3、Resize,其些元件的尺寸变了。
4、StyleChange,如果CSS的属性发生变化了。

tip
本文通过对从输入URL 到页面展现对了过程详细的归纳,这个过程设计较多的知识点,我对部分做了归纳,如果有不足之处希望能够指出
参考文献
从输入url到页面展现发生了什么?

文章分类
前端
文章标签