从输入URL到页面可交互的过程探究之一:从服务端到客户端

原文:alistapart.com/article/ser…前端

最近发现国外有一个系列,专门探究从输入URL到页面可交互的详细过程,是一份干货十足的好资料。笔者决定分为四篇文章对其进行有删减地翻译,只但愿能对你们有所帮助,毕竟这是前端必备的知识点,也是容易忽略掉某些细节的知识点。事先声明,这个系列彻底由笔者手翻,若有翻译不当的地方,恳请读者给出改进意见!数据库

接下来开始第一篇——从服务端到客户端跨域

在浏览器执行任何工做以前,它须要先知道访问的是哪里。有几种方法能够实现访问:在地址栏中输入URL、点击(或触碰)一个页面上或其余app中的超连接、或者点击你的收藏。不管是哪一种状况,都会触发一个动做——导航。导航永远是网页中交互的第一步,由于它触发了以下一系列事件的连锁反应直至网页被加载。浏览器

初始化请求

一旦URL被提供给浏览器去加载,如下这些事情就会悄悄在背后发生:缓存

检查HSTS

首先,浏览器须要判断这个URL是否明确为HTTP(不安全)协议。若是它是一个HTTP的请求,那么浏览器则须要检查这个域名是否在HSTS的清单中(HTTP Strict Transport Security——严格安全传输)。这个清单包含了一个预加载好的名单以及你以前访问过的使用HSTS的网站名单,它们都是存放在浏览器中的。若是你请求的HTTP开头的host处于在HSTS清单中,那这个请求会被强制转为HTTPS开头的URL而非HTTP。这就是为何你会发现当你试图在一个现代浏览器中输入http://www.bing.com 会被转为https://www.bing.com。安全

检查SERVICE WORKERS

接着,浏览器须要判断service worker是否能够用来处理请求——这对于那些离线的没有网络链接的用户来讲相当重要。Service workers相对来说是比较新的浏览器特性。它经过对网络请求的拦截来提供离线应用的能力,这些请求均可以被保留在脚本控制的缓存中。这是颇有用的,由于它使网站可以更好地控制什么时候使用缓存的项目。这些缓存是跟域名绑定的,这意味着每一个域均可以有本身的缓存黑盒,并与其余域的缓存隔离开。服务器

当一个页面被访问时,能够注册一个Service worker,这个动做是由一个工做线程来完成的,它能够把service worker的注册和URL映射记录在本地数据库中。要判断一个service worker是否被安装,只需在这个本地数据中查找是否有对应的URL。若是为service worker查到了对应的URL,它就会被容许处理请求的回应。而若是浏览器支持Navigation Preload的新特性,且开发者使用了它,那么浏览器会同时去发起首次导航请求。这是有好处的,由于它避免了浏览器由于service worker启动过慢而对页面渲染的影响。微信

当浏览器发现没有service worker来处理初始化请求时,就会继续网络请求层。网络

检查网络缓存

浏览器会经过网络请求层检查缓存中是否存在全新的响应。这常常是由响应头中的Cache-Control字段决定的,字段中设置的max-age值能够决定缓存多久会刷新,而no-store字段能够代表是否应该被缓存。可想而知,若是浏览器在缓存中找不到任何东西,那么就须要进行网络请求了。而若是在缓存中有一个全新的响应,它就会被当即返回以用于页面加载。若是存在一个不够“新”的资源,那么浏览器会把这个请求转为一个附带条件的校验请求,也就是请求头带上If-Modified-Since或者If-None-Match去告诉服务端当前浏览器存的是哪一个版本的缓存。服务端则能够返回HTTP 304状态码(没有更改)告诉浏览器这个缓存是最新的,不带响应正文;或者返回HTTP 200状态码告诉浏览器这个缓存资源已通过期了,并直接返回最新的资源app

检查网络链接

若是如今有一个和主机、端口创建起链接的请求,那么它会被浏览器复用而不是从新去创建一个,不然,浏览器会走网络层以了解是否须要执行DNS(域名系统)查询。这个动做的具体流程是,先寻找本地的DNS缓存(存储在你的设备上),而后根据DNS缓存是否过时来决定是否访问远程域名服务器(它们由互联网服务提供商ISP分配主机地址),域名服务器最终会返回准确的IP地址给浏览器进行链接。

某些状况下,浏览器可以预先知道哪些域名会被访问,从而先准备好对这些域名的链接。一个网页能够经过在link标签中使用资源提示(resource hints),好比rel="preconnect" 来提示浏览器提早准备好链接。在以下场景中,资源提示是颇有用的,好比一个用户在必应的搜索结果页,而一般的预期中,前几条搜索结果是最有可能被用户访问的。此时,提早准备好对那些域名的链接能够在那些网页被点击以后节省掉DNS查询和域名链接的消耗。

创建起链接

浏览器如今能够与服务器创建起链接了,且服务端知道本身须要从客户端接收和发送消息了。若是咱们是使用TLS,咱们须要执行一次TLS握手流程以验证服务器提供的证书。

发送请求给服务器

第一个经过这个链接发起的请求叫作顶级页面请求。一般状况,这个请求的资源会是一个HTLML文件,从服务器返回到客户端

处理响应

当响应以数据流的形式到达客户端后,客户端就开始进行解析了。首先,浏览器会检查响应头。HTTP头部是以键值对的形式做为HTTP响应的一部分。若是响应头指示要进行重定向(好比,经过Location字段),浏览器就会再一次进行导航并回到最初的那一步,检查是否须要执行HSTS的升级(为HTTPS)。

若是服务器的响应数据被压缩或分块了,浏览器会尝试对它进行解压和合并。

待响应被解读完成后,浏览器还会并行地将其写入网络缓存中。

接着,浏览器会搞清发送过来的文件的MIME类型,这样它才能以适当的方式去加载这份文件。好比,一份图片文件会原封不动地被加载进来,但HTML文件则会被执行解析和渲染。若是HTML解析器被调用了,那么它会扫描出那些可能要下载的资源文件的URL,以便浏览器在页面渲染以前就能够开始去下载。这一部分的更多细节会在系列文章的下一篇中具体展开。

截至目前,被请求的导航URL已经输入到了浏览器的历史中,这样它就能够被用于浏览器导航的前进和后退功能了。

这里有一张更详细的流程图,它可让你对目前讨论的内容有个整体的概览:

如你所知的,页面会继续发起请求,由于页面上还有不少对总体体验很重要的子资源,好比图片,脚本,和样式表。另外,这些子资源中引用到的其余资源,好比背景图片(CSS中引用的),或者其余由fetch()import()AJAX请求发起的资源。若是没有这些的话,咱们将只能看到一个原始的无交互的空页面。

再谈缓存

刚刚已经提到,浏览器会管理网络缓存,以便在多种场景下能对下载好的资源的重复利用。这对那些长久不更新的资源尤为有用,好比logo和第三方的脚本文件。咱们应该尽量地利用好这些缓存,由于这有利于减小对外的网络请求数,取而代之的是本地的可复用的缓存资源。

响应头中的Cache-Control字段控制着浏览器的缓存逻辑。某些状况下,你能够谨慎地告诉浏览器彻底不要进行缓存,好比使用Cache-Control: no-store,由于这个资源在预期中是一直在变化的。另外一种状况下,当给定URL的响应内容永远不会变化时,咱们能够设置Cache-Control: immutable以便浏览器能够永远地缓存它。实际应用中,当咱们使用不一样的URL来指向不一样版本的同一份资源时,咱们就能够采用这种作法,而非对同一个URL的资源进行更改,由于被缓存的版本会一直被使用且不会去发送请求。

Origin模型

Origin是由协议,主机名和端口共同组成的。例如,www.bing.com:443 这个origin是由https的协议, www.bing.com 的主机名和443的端口组成的。只要其中任何一个部分有差别,那么在二者进行比较时,都会被认为是不一样源的。好比https://images.bing.com:443 和 www.bing.com:80 就是不一样源的。

Origin对于浏览器来讲是很重要的概念,由于它定义了数据是如何被隔离和保护的。大多数状况,为了安全考虑,浏览器会强制使用同源策略,意味着一个源没法访问另外一个源的数据。就像上面提到的两个源——images.bing.com:443www.bing.com:80 ,它们互相都没法访问对方的缓存(service worker的)。

若是bing.com想要从microsoft.com加载一个Javascript文件,它就须要在实行同源策略的浏览中发起一个跨域资源请求。想要容许这种操做的话,microsoft.com就须要与bing.com经过指定CORS(跨域资源共享)的头部进行合做。

总结

既然你已经明白了资源如何从服务器走到客户端以及之间的全部细节,那么请继续关注网页加载的下一步:从HTML标签转为DOM。

ps:欢迎关注微信公众号——前端漫游指南,会按期发布优质原创文章和译文,关注公众号福利:回复666能够得到精选前端进阶电子书,感谢~

相关文章
相关标签/搜索