赞
踩
从我们输入URL并按下回车键到看到网页结果之间发生了什么?换句话说,一张网页,要经历怎样的过程,才能抵达用户面前?下面来从一些细节上面尝试一下探寻里面的秘密。
说到输入URL,当然是从手敲键盘开始。对于键盘,生活中用到的最常见的键盘有两种:薄膜键盘、机械键盘。
键盘传输信号到操作系统后便会触发硬件中断处理程序。硬件中断是操作系统中提高系统效率、满足实时需求的非常重要的信号处理机制,它是一个异步信号,并提供相关中断的注册表(IDT)与请求线(IRQ)。键盘被按压时,将通过请求线将信号输入给操作系统,CPU在当前指令结束之后,根据注册表与信号响应该中断并利用段寄存器装入中断程序入口地址。具体可参看操作系统与汇编相关书籍。
当然本文主要不是介绍硬件与操作系统中的细节,前言只是想说明,从输入URL到浏览器展现结果页面之间有太多底层相关的知识,怀着一颗敬畏的心并且在有限的篇幅中是无法详细阐述的,所以本文会将关注点放在一个稍高的角度上来看,从浏览器替我们发送请求之后到看到页面显示完成这中间中发生了什么事情,比如DNS解析、浏览器渲染。
下图是从用户发送一条请求开始到最终看到页面的流程简化图,本文将以该请求为线索,在下面一步一步探索其中的细节。
比如我按下一个“b”键,会出现很多待选URL给我,第一个便是百度。那么其实是在浏览器接收到这个消息之后,会触发浏览器的自动完成机制,会在你之前访问过的搜索最匹配的相关URL,会根据特定的算法,甚至涉及到机器学习来分析出你有可能想搜索的关键字,显示出来供用户选择。
依据上述键盘触发原理,一个专用于回车键的电流回路通过不同的方式闭合了。然后触发硬件中断,随之操作系统内核去处理对应中断。省略其中的过程,最后交给了浏览器这样一个“回车”信号。那么浏览器(本文涉及到的浏览器版本为Chrome 61)会进行以下但不仅限于以下炫酷(乱七八糟)的步骤:
DNS的查询方式是:按根域名->顶级域名->次级域名->主机名这样的方式来查找的,对于某个URL,如下所示
查询步骤为:
以www.google.com为例,下面是在阿里云实例上作的完整的DNS查询过程:
拿到IP之后,还需要拿到那台服务器的MAC地址才行,在以太网协议中规定,同一局域网中的一台主机要和另一台主机进行直接通信,必须要知道目标主机的MAC地址。所以根据ARP(根据IP地址获取物理地址的一个TCP/IP协议)获取到MAC地址之后保存到本地ARP缓存之后与目标主机准备开始通信。具体细节参见维基百科DHCH/ARP。
为什么握手一定要是三次?
这样就保证了A与B之间既能相互发送请求也能相互接收解析请求。同时避免了因为网络延迟产生的重复连接问题,比如A发送一次连接请求但网络延迟导致这次请求是在A重发连接请求并完成与B通信之后的,有三次握手的话,B返回的建立请求A就不会理睬了。
短连接与长连接?
上图是一个短连接的过程演示,对于长连接,A与B完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。另外,由于长连接的实现比较困难,需要要求长连接在没有数据通信时,定时发送数据包(心跳),以维持连接状态,并且长连接对于服务器的压力也会很大,所以推送服务对于一般的开发者是非常难以实现的,这样的话就出现了很多不同的大型厂商提供的消息推送服务。
为了优化网站访问速度并减少服务器压力,通常将html、js、css、文件这样的静态文件放在独立的缓存服务器或者部署在类似Amazon CloudFront的CDN云服务上,然后根据缓存过期配置确定本次访问是否会请求源服务器来更新缓存。
负载均衡具体实现有多种,有直接基于硬件的F5,有操作系统传输层(TCP)上的 LVS,也有在应用层(HTTP)实现的反向代理(也叫七层代理),下面简单介绍一下最后者。
在请求发送到真正处理请求的服务器之前,还需要将请求路由到适合的服务器上,一个请求被负载均衡器拿到之后,需要做一些处理,比如压缩请求(在nginx中gzip压缩格式是默认配置在nginx.conf内的,所以默认开启,如果不对数据量要求特别精细的话,默认配置完全可以满足基本需求)、接收请求(接收完毕后才发给Server,提高Server处理效率),然后根据预定的路由算法,将此次请求发送到某个后台服务器上。
其中需要提到的一点是反向代理,先理解一下正向代理的原理:正向代理是将自己要访问的资源告诉Proxy,让Proxy帮你拿到数据返回给你,Proxy服务于Client,常用于翻墙和跨权限操作。反向代理也是将自己要访问的资源告诉Proxy,让Proxy帮你拿到数据返回给你,但是Proxy会将请求接受完毕之后发送给某一合适的Server,这个时候Client是不知道是根据什么规则并且也不知道最后是哪一个Server服务于它的且Proxy服务于Server,所以叫反向代理,常用于负载均衡、安全控制。
对于HTTPD(HTTP Daemon)在服务器上部署,最常见的 HTTPD 有 Linux 上常用的 Apache 和 Nginx。对于Java平台来说,Tomcat是Spring Boot也会默认选用的Servlet容器实现,以Tomcat为例,对于请求的处理如下:
浏览器的功能是从服务器上取回你想要的资源,然后展示在浏览器窗口当中。资源通常是 HTML 文件,也可能是 PDF,图片,或者其他类型的内容。也可以显示其他类型的插件(浏览器扩展)。例如显示PDF使用PDF浏览器插件。资源的位置通过用户提供的 URI(Uniform Resource Identifier) 来确定。
浏览器解释和展示 HTML 文件的方法,在 HTML 和 CSS 的标准中有详细介绍。这些标准由 Web 标准组织 W3C(World Wide Web Consortium) 维护。
下面会以Chrome中使用的浏览器引擎Webkit为例,根据上图来简单介绍浏览器的渲染。具体解析、渲染会涉及到非常多的细节,请参考HTML5渲染规范和对应的页面GPU渲染实现。
浏览器拿到具体的HTML文档之后,需要调用浏览器中使用的浏览器引擎中处理HTML的工具(HTML Parser)来将HTML文档解析成为DOM树,将以便外部接口(JS)调用。
<style>
标签包含的内容以及style属性的值解析完成后,浏览器引擎会通过DOM树和CSS Rule树来构造渲染树。渲染树的构建会产生Layout,Layout是定位坐标和大小,是否换行,各种position, overflow, z-index属性的集合,也就是对各个元素进行位置计算、样式计算之后的结果。
接下来,根据渲染树对页面进行渲染(可以理解为“画”元素)。
当然,将这个渲染的过程完成并显示到屏幕上会涉及到显卡的绘制,显存的修改,有兴趣的读者可以深入了解。本文只是将对于我们软件开发者来说需要了解的部分进行总结,还有很多过程与机制没有提到,github上的这个项目期待你的贡献。
参考
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。