从输入网址到页面呈现都发生了什么?

2018年4月25日19:19:48 发表评论 408 阅读
摘要

众所周知,我们在输入一个网址的时候,浏览器会给我们展示一个页面。那么我们在输入网址到页面展示,过程中都发生了什么呢?

大概包含以下几个部分:

    1. DNS解析
    2. 浏览器向web服务器发送一个HTTP请求
    3. TCP连接
    4. 服务器永久重定向响应,浏览器跟踪重定向地址
    5. 服务器处理请求并返回HTTP报文
    6. 浏览器解析渲染页面

具体过程-DNS解析

1)什么是DNS解析?

 DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。

  通俗的讲,我们更习惯于记住一个网站的名字,比如www.163.com,而不是记住它的ip地址,比如:1.1.1.1。而计算机更擅长记住网站的ip地址,而不是像www.163.com等链接。因此,DNS就相当于一个电话本,比如你要找www.163.com这个域名,那我翻一翻我的电话本,我就知道,哦,它的电话(ip)是1.1.1.1。

注意:域名(Domain Name System)和URL(统一资源定位符)的区别在于,域名是一台或一组服务器的名称,用来确定服务器在 Internet 上的位置;URL 是统一资源定位符,用来确定某一个文件的具体位置,www.baidu.com是域名,www.baidu.com/打开的页面名字/ 是URL。

2)DNS解析

 1、请求一旦发起,浏览器首先要做的事情就是解析这个域名,一般来说,浏览器会首先查看本地硬盘的 hosts 文件,看看其中有没有和这个域名对应的规则,如果有的话就直接使用 hosts 文件里面的 ip 地址。

      2、如果在本地的 hosts 文件没有能够找到对应的 ip 地址,浏览器会发出一个 DNS请求到本地DNS服务器 。本地DNS服务器一般都是你的网络接入服务器商提供,比如中国电信,中国移动。

    3、查询你输入的网址的DNS请求到达本地DNS服务器之后,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果,此过程是递归的方式进行查询。如果没有,本地DNS服务器还要向DNS根服务器进行查询。

  4、根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。这种过程是迭代的过程。

  5、本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。

  6、最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。

从输入网址到页面呈现都发生了什么?

浏览器向web服务器发送一个HTTP请求

其实这部分又可以称为前端工程师眼中的HTTP,它主要发生在客户端。发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议中发送到服务器指定端口(HTTP协议80/8080, HTTPS协议443)。HTTP请求报文是由三部分组成: 请求行请求报头请求正文

格式如下:

Method Request-URL HTTP-Version CRLF


GET / HTTP/1.1

常用的方法有: GET, POST, PUT, DELETE, OPTIONS, HEAD

TCP连接

在TCP/IP协议中TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

完成三次握手,客户端与服务器开始传送数据。

从输入网址到页面呈现都发生了什么?

说明为什么需要三次握手?

《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”

   书中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。

  假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”。主要目的防止server端一直等待,浪费资源。

服务器永久重定向响应,浏览器跟踪重定向地址

服务器的永久重定向响应(从 http://example.com 到 http://www.example.com),这里是为了SEO考虑,在此不做赘述。

服务器处理请求并返回HTTP报文

自然而然这部分对应的就是后端工程师眼中的HTTP。后端从在固定的端口接收到TCP报文开始,这一部分对应于编程语言中的socket。它会对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用。这一部分工作一般是由Web服务器去进行。

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 表示服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常

浏览器解析渲染页面

在浏览器没有完整接受全部HTML文档时,它就已经开始显示这个页面了,浏览器是如何把页面呈现在屏幕上的呢?不同浏览器可能解析的过程不太一样,这里我们只介绍webkit的渲染过程,下图对应的就是WebKit渲染的过程,这个过程包括:

解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树

从输入网址到页面呈现都发生了什么?

浏览器在解析html文件时,会”自上而下“加载,并在加载过程中进行解析渲染。在解析过程中,如果遇到请求外部资源时,如图片、外链的CSS、iconfont等,请求过程是异步的,并不会影响html文档进行加载。

  解析过程中,浏览器首先会解析HTML文件构建DOM树,然后解析CSS文件构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。这个过程比较复杂,涉及到两个概念: reflow(回流)和repain(重绘)。

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

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

从输入网址到页面呈现都发生了什么?

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

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

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

参考文献:
http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/
https://segmentfault.com/a/1190000006879700#articleHeader3
http://www.cnblogs.com/xianyulaodi/p/6547807.html#_label2


 

  • 我的微信号
  • 深入交流一下吧
  • weinxin
  • 我的微信公众号
  • 添加公众号了解更多动态
  • weinxin
舍得

发表评论

不高兴 彩虹 吃瓜 丢翔 乖 滑稽 花心 惊哭 惊讶 挤眼 酷 伤心 帅吗? 礼物 玫瑰 怒 生气 喷 睡觉 太开心 小九九 啊
太阳 吐舌 委屈 笑眼 星星月亮 心碎 咦 阴险 疑问 真棒 偷笑 斜眼笑 震惊 略 哈欠 无奈哭 抠鼻 哼 期待 懒得理你 爱心 蜡烛