从输入url到页面展示到底发生了什么

这篇文章很多都是参考别人的,然后进行总结,并提供相应知识点的学习资料
从输入url到页面展示总共经过如下几个过程:

  1. 域名解析(获得IP地址)
  2. 向WEB服务器发送HTTP请求
  3. 服务器处理请求
  4. 服务器返回HTTP响应
  5. 浏览器显示页面信息

一、输入地址

当输入url地址后,浏览器已经在智能匹配地址了,会从历史记录、书签或缓存中查找,如果找到了,会从缓存中调出页面显示出来,在你还没有按“enter”之前

image

二、浏览器查找域名的IP地址

浏览器查找域名的IP地址按照以下几个步骤进行(这是你输入url,按了enter之后):

  1. 首先会在浏览器的缓存中查找是否有该域名对应的IP地址,如果有,则直接返回该IP地址;如果没有,则查找本地硬盘上的hosts文件中是否有,如果有,则返回对应的IP地址;如果没有,则查找路由器缓存中是否有对应的IP地址,如果有,则返回;
  2. 如果在浏览器缓存中、hosts文件中、路由器缓存中都没有找到ip地址,则浏览器会发起一个DNS请求到本地DNS服务器,本地DNS服务器一般是由你的网络接入服务器商提供,如:电信、移动;
  3. DNS请求到达本地DNS服务器后,本地DNS服务器会先在自己的缓存中查找,如果找到了就返回找到的IP,这个过程是以递归的方式进行的;如果没有,则本地DNS服务器继续向根DNS服务器发起请求;
  4. 根DNS服务器并没有记录域名与IP的对应关系,而是告诉本地DNS服务器,可以到哪个顶级域名服务器上查询,并给出该顶级域名服务器的地址,此过程是以迭代的方式进行的;
  5. 本地DNS继续向顶级域名服务器发出查询请求,顶级域名服务器接收到请求后,会告诉本地DNS到权限域名服务器上去查询;
  6. 本地DNS继续向权限域名服务器发出查询请求,权限域名服务器查询到域名对应的IP后,将IP地址返回给本地DNS,本地DNS接收后将其保存到自己的缓存中,以备下次查询,提高查询速度;至此,一个IP地址的查询就此结束;
    DNS解析是一个递归查询的过程

    注意DNS域名解析是以递归的方式进行的

知识拓展

1. 什么是DNS
DNS(domain name system,域名系统):因特网上域名和IP地址相互映射的分布式数据库;简单理解就是域名与IP地址的对照表,因为域名(如:www.google.com)对于我们而言,更便于记忆,但是机器却不擅长这种表达方式,因此需要将域名转换为IP地址,以便于机器识别, 这便有了DNS。
2. 根域名服务器
根服务器是架设互联网的必须设施,管理互联网的主目录,全球共有13套根域名服务器
3. 递归查询
客户端主机向本地域名服务器的查询是递归查询;所谓递归查询:客户端主机查询的域名地址无法在本地域名服务器中找到,因此本地域名服务器就以DNS客户端的身份向其他根域名服务器发起请求,进行查询,而不是让客户端主机去一直查询;
递归查询的结果要么是返回的IP地址,要么是报错,表示无法查询到地址
4. 迭代查询
本地域名服务器向根服务器、顶级域名服务器和主机域名服务器发起的查询请求就是迭代的过程,如:本地域名服务器向根服务器发起查询请求,根服务器中会告诉本地域名服务器:”我这里没有你要找的内容,你去顶级域名服务器上找吧“,并将顶级域名服务器的地址返回给本地域名服务器,本地域名服务器接收到后,继续向顶级域名服务器发送请求;顶级域名服务器要么返回ip地址,要么告诉本地域名服务器下一步要向哪个权限域名服务器发送请求,直到找到ip地址或找不到ip返回报错信息,然后信息返回给客户端主机;
下图给出了这两种查询的差别


递归过程:主机→本地DNS服务器→其他DNS服务器(如:我要找一个苹果吃,找到了A,问A有没有,A说我帮你去找B,B可能有,果真B有,然后B将苹果给了A,A再将苹果给我,这就是递归)
迭代过程:本地DNS服务器→根服务器,本地DNS服务器→顶级域名服务器,本地DNS服务器→权限域名服务器;(如:我要找一个苹果,找到了A,A说我也没有,B可能有,你去找B吧;我又找B,B说我也没有,你去找C吧,我又去找C,终于找到了苹果,这就是迭代的过程)
整体图:
Paste_Image.png

域名服务器的划分:

1. 根域名服务器
全球总共有13套根服务器设备;它是最重要的域名服务器,它知道所有顶级域名服务器的域名和IP地址,如果本地域名服务器无法对域名进行解析,那么都必须求助于它来进行解析
2. 顶级域名服务器
负责管理在该顶级域名服务器注册的所有二级域名。当收到DNS请求后,就给出相应的回答(可能是最后的结果,也可能是下一步应当找的域名服务器的IP地址)
3. 权限域名服务器
假设一个公司有abc.com和y.abc.com这么两个网址,那么该网址对应的权限域名服务器中包含有这两个网址映射的IP地址,权限服务器就是这样的存在,可能理解不正确;理解如下几个图吧
4. 本地域名服务器
每个因特网服务提供商ISP,或大学,甚至大学里的一个系,都可以拥有本地域名服务器
5. DNS域名称空间的组织方式
我们在前面有说到根DNS服务器,域DNS服务器,这些都是DNS域名称空间的组织方式。按其功能命名空间中用来描述 DNS 域名称的五个类别的介绍详见下表中,以及与每个名称类型的示例


6. DNS负载均衡
当用户访问量巨大时,同时访问主机将会使主机崩掉,因此使用DNS负载均衡技术解决这个问题,
原理:在DNS服务器中为同一个主机分配多个IP地址(也就是多个服务器),当进行DNS解析时,通过算法根据主机的负载情况,返回IP地址,这里面涉及到一个主机记录(也叫A记录),它主要用于将特定的主机名映射到特定的IP地址上;可查看DNS负载均衡资料

域名服务器结构图
因特网的域名空间

三 、浏览器向WEB服务器发送Http请求

拿到域名对应的IP地址之后,浏览器会以一个随机的端口(1024~65535)向服务器(Niginx, Apache等)的WEB程序80端口/8080端口(HTTP协议使用80端口/8080端口,HTTPS使用443端口)发起TCP连接请求。连接请求到达服务器端后,通过网卡,进入到内核的TCP/IP协议栈,还有可能要经过防火墙,进入WEB程序,最终建立TCP/IP连接。

TCP连接如图所示:



建立连接后,会发送一个HTTP请求,HTTP请求包含的信息可以分成如下三部分:

  • 请求行(包含请求的方法、URL地址和协议版本)
  • 请求头(Request Header)
  • 请求正文
请求行

请求行的格式如下:
Method Request-URL HTTP-Version CRLF
如: GET index.html HTTP/1.1

  • 请求的方法:GET或POST(这两个是常用的),不常用的有:PUT 和 DELETE 、HEAD、OPTION以及 TRACE 方法,一般的浏览器只能发起 GET 或者 POST 请求。
  • URL地址: 可以理解为我们要访问的服务器上的文件地址
  • 协议版本:常用的是HTTP1.1
请求头

作用:请求头允许客户端向服务器端传请求的附加信息和客户端信息
PS: 客户端不一定指浏览器,有时也指Linux下的CURL命令行以及HTTP测试工具

常见的请求头有:Accept、Accept-Language、Accept-Encoding、Accept-Charset、connection、Content-Type、Authorizaion、Cookie、User-Agent等

百度的HTTP请求

上图是截获的百度HTTP请求,Accept用于指定客户端接收哪些类型的信息,Accept-Encoding指定接受的编码格式,Connection指定为Keep-alive,表示本次HTTP请求结束后,不要断口TCP连接,这样当下次HTTP请求使用相同的TCP通道时,可以不需要重新连接,节省TCP连接时间

请求正文

当使用POST或PUT方式时,表示客户端需要向服务器端传输数据,传输的数据存放在请求正文中,同时,请求头中也会包含一些与请求正文相关的数据;例如:当请求的数据采用json的数据格式时,需要设置请求头的Content-Type:Application/json。

注意:请求头和请求正文之间有一个空行,这个空行很重要,表示请求头的结束。

如下是完整的HTTP请求:


HTTP请求.png

知识拓展

  1. 发送HTTP请求使用的随机端口:
    这里指的端口均是逻辑端口,也就是TCP/IP协议中的端口,端口范围为:0~65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。一般 0 ~ 1023端口是固定分配给一些服务的,所以我们使用1024~65535的端口,关于端口的介绍可以查看计算机网络端口的定义这篇文章
  1. 关于TCP的三次握手和四次挥手可以查看这两篇文章:socket编程三次握手socket编程-四次握手断开连接
  2. 为什么握手需要三次,而挥手要四次呢?
    在建立连接时,服务器端接收到客户端的SYN后,将ACK和Seq打包发给了客户端;而断开连接时,服务器端正处于LISTEN监听状态, 接收到客户端的FIN请求后,服务器端发送ACK给客户端作为响应,相当于就是告诉客户端:"
    我知道你要断开连接了(这只表示客户端不再发送数据,但是还可以接收数据),但是我还有些数据没有发送完成",等服务器发送完成数据后,会发送FIN给客户端,告诉它:“数据已经发送完成了,我们可以彻底断开连接了“,客户端接收到FIN后,再发送ACK给服务器,至此,两者断开连接

四、浏览器的永久重定向响应

拿访问google为例说明
我输入的网址是 http://google.com服务器接收到请求后,给浏览器响应301永久重定向,浏览器转而访问 http://www.google.com而不是http://google.com

  1. 什么是重定向?
    简单理解就是将我输入的网址引向另一个网址;
  2. 为什么产生重定向?
  • 如果一个网站有两个网址,那么分配到每个网址上的搜索链接数就会减少,不利于排名
  • 缓存友好型变差;因为要将同一个网站的多个地址均保存到缓存中。
  1. 301和302的区别
  • 共同点:都表示重定向,也就是浏览器拿到这个状态码之后,均会跳转到新的URL地址,这个地址从服务器响应的Location中获得
  • 不同点:301表示永久重定向,也就是原网址资源不可用了,搜索引擎在抓取新内容的同时,也会将旧网址重定向到新网址。
    302表示旧地址A的资源还在(仍然可以访问),这个重定向只是暂时的从地址A跳转到地址B,搜索引擎在抓取新内容而保存旧的网址
    这里面涉及到搜索引擎的原理,可以参考如下资料:
    搜索引擎原理
    301和302跳转的区别
    一个很不错的关于SEO优化的个人网站
    《这就是搜索引擎:核心技术详解》了解基本的搜索引起原理
  1. 重定向的原因
  • 网站调整(如改变目录结构)
  • 网页被移到另一个网址
  • 网页的扩展名改变(如需要把.php改为html)
    如果存在上述原因,而不进行重定向,那么访问者访问的是旧的网址,要么不能得到网站的最新信息,要么出现404找不到主页的错误,访问量就被白白浪费掉了;再者,当一个网站申请了多个网址时,它们都需要导向主站点,这时候也需要用到重定向
  1. 什么时候进行301或302的跳转
    当网站只是临时的移到另一个新的位置,可以使用302;当使用301时,说明原来的网址已经被移除不存在了。

五、服务器处理请求

经过以上层层步骤之后,我们的请求最终到了服务器,服务器是如何处理请求?

后端服务器从固定的端口接收到TCP报文后,开始对TCP报文进行处理,对HTTP协议进行解析,然后将相应的数据封装为HTTP Request对象,供上层使用。

对于大型的网站,为了防止访问量过大对应用服务器的冲击,使得应用服务器挂掉,所以一般都会设置反向代理服务器(如:Nginx),用户发送的请求并不是直接进入到应用服务器,而是会先到达反向代理服务器,然后由反向代理服务器根据实际情况将用户请求传递给某个应用服务器,然后再将结果返回给客户端;这样也可以防止一台服务器挂掉了,而不会影响到网站的正常使用。

如图所示:

通过Nginx反向代理服务器,我们的请求到达WEB服务器,服务器端脚本处理我们的请求,访问数据库,获取需要获取的内容等,这里涉及到服务器后端很多的复杂处理。

知识拓展

  1. 什么是反向代理服务器
    客户端的本来可以直接通过HTTP协议访问应用服务器,但是网站管理员在中间添加了一个Nginx,这样客户端会先将请求发送到Nginx,Nginx请求应用服务器,然后将结果返回给客户端,Nginx就扮演着反向代理服务器器的角色。
Paste_Image.png

六、服务器返回一个HTTP响应

经过上面的几个步骤,服务器收到客户端请求,并已经处理,这时候需要把处理结果返回,也就是返回一个HTTP响应。
HTTP响应与HTTP请求类似,也包括如下三个部分:

  • 状态行
  • 响应头
  • 响应正文
一个HTTP响应
状态行:

状态行由:协议版本代表状态的数字码以及状态描述,各元素之间以空格隔开
状态行由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。
格式: HTTP-Version Status-Code Reason-Phrase CRLF
例如: HTTP/1.1 200 OK \r\n
| -协议版本:是用http1.0还是其他版本
| -状态描述:状态描述给出了关于状态代码的简短的文字描述。比如状态代码为200时的描述为 ok
| -状态代码:状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。如下:

1xx:信息性状态码,表示服务器已接收了客户端请求,客户端可继续发送请求。

  • 100 Continue
  • 101 Switching Protocols

2xx:成功状态码,表示服务器已成功接收到请求并进行处理。

  • 200 OK 表示客户端请求成功
  • 204 No Content 成功,但不返回任何实体的主体部分
  • 206 Partial Content 成功执行了一个范围(Range)请求

3xx: 重定向状态码,表示服务器要求客户端重定向。

  • 301 Moved Permanently 永久性重定向,响应报文的Location首部应该有该资源的新URL
  • 302 Found 临时性重定向,响应报文的Location首部给出的URL用来临时定位资源
  • 303 See Other 请求的资源存在着另一个URI,客户端应使用GET方法定向获取请求的资源
  • 304 Not Modified 服务器内容没有更新,可以直接读取浏览器缓存
  • 307 Temporary Redirect 临时重定向。与302 Found含义一样。302禁止POST变换为GET,但实际使用时并不一定,307则更多浏览器可能会遵循这一标准,但也依赖于浏览器具体实现

4xx:客户端错误状态码,表示客户端的请求有非法内容。

  • 400 Bad Request 表示客户端请求有语法错误,不能被服务器所理解
  • 401 Unauthonzed 表示请求未经授权,该状态代码必须与 WWW-Authenticate 报头域一起使用
  • 403 Forbidden 表示服务器收到请求,但是拒绝提供服务,通常会在响应正文中给出不提供服务的原因
  • 404 Not Found 请求的资源不存在,例如,输入了错误的URL

5xx:服务器错误状态码,表示服务器未能正常处理客户端的请求而出现意外错误。

  • 500 Internel Server Error 表示服务器发生不可预期的错误,导致无法完成客户端的请求
  • 503 Service Unavailable 表示服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常
响应头:

响应头部:由关键字/值对组成,每行一对,关键字和值用英文冒号”:”分隔,典型的响应头有:

响应头部
响应正文

包含着我们需要的一些具体信息,比如cookie,html,image,后端返回的请求数据等等。这里需要注意,响应正文和响应头之间有一行空格,表示响应头的信息到空格为止,下图是fiddler抓到的请求正文,红色框中的:响应正文:

响应正文

知识拓展

  1. TCP/IP、HTTP协议
    简单的说就是TCP/IP、HTTP位于OSI模型的不同层,TCP位于传输层,IP位于网络层,而HTTP位于应用层;
    具体可查看:TCP/IP、HTTP协议的区别

七、浏览器显示HTML

在浏览器还没有完整的接受HTML文档时,它就已经开始显示页面了,不同浏览器解析的流程不同,以webkit的渲染过程为例:

用户请求的HTML文本(text/html)通过浏览器的网络层到达渲染引擎后,渲染工作开始。

渲染过程

详细流程图
  


渲染详细流程图

主要分为以下四个部分:

  1. 浏览器把获取到的HTML代码解析成1个DOM树,HTML中的每个tag都是DOM树中的1个节点,根节点就是我们常用的document对象。DOM树里包含了所有HTML标签,包括display:none隐藏,还有用JS动态添加的元素等。

  2. 浏览器把所有样式(用户定义的CSS和用户代理)解析成样式结构体,在解析的过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式,而FF会去掉_开头的样式。

  3. DOM Tree 和样式结构体组合后构建render tree, render tree类似于DOM tree,但区别很大,render tree能识别样式,render tree中每个NODE都有自己的style,而且 render tree不包含隐藏的节点 (比如display:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到 render tree中。注意 visibility:hidden隐藏的元素还是会包含到 render tree中的,因为visibility:hidden 会影响布局(layout),会占有空间。根据CSS2的标准,render tree中的每个节点都称为Box (Box dimensions),理解页面元素为一个具有填充、边距、边框和位置的盒子。

  4. 一旦render tree构建完毕后,浏览器就可以根据render tree来绘制页面了。

回流与重绘
  1. 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。

  2. 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。

注意:回流必将引起重绘,而重绘不一定会引起回流。回流可以理解为render树的结构发生了变化,需要重新构建;而重绘就是结构没有变化,只是一些对结构布局没有产生影响的元素发生了变化(如:字体颜色)

渲染过程中的JS处理

浏览器在构造页面时,当浏览器从服务器端接收到HTML文档时,会从上到下依次解析HTML文档,转换为DOM树,在转换过程中,如果发现某个Node(节点)引用了CSS、IMG,则会发起一个request(不知道这个是不是指HTTP请求?)去请求CSS或IMG,继续执行下面的HTML转换,而不需要等待request的返回,当request返回后,只需要把相应的内容放到对应的Node上即可。但是当引用了JS的时候,浏览器发起一个JS的request请求后,会一直等待该请求的返回;因为浏览器需要构建一个稳定的DOM树,而JS代码很有可能会改变DOM结构,如使用document.write或appendChild,甚至直接使用location.href进行跳转,浏览器为了防止出现这种情况, 所以会阻塞后续资源的下载。

JS的解析是由浏览器中的JS解析引擎完成的,比如谷歌的是V8。JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始。但是又存在某些任务比较耗时,如IO读写等,所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)
  JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。

知识拓展

  1. 关于页面回流与重绘可以参考这篇文章:
    页面重绘和回流以及优化
  1. 关于JS的加载解析,参考:
    如何加载JS,JS应该放在什么位置?
  2. WEB前端底层知识--浏览器是如何工作的

参考资料:
计算机网络第5版——谢希仁
what-really-happens-when-you-navigate-to-a-ur
从输入URL到页面加载发生了什么
老生常谈-从输入url到页面展示到底发生了什么
浅谈一个网页打开的全过程(涉及DNS、CDN、Nginx负载均衡等)

推荐阅读更多精彩内容