我建议我的客户加快网站访问速度的第一件事似乎是一个悖论:首先,您必须在主机上放置静态资源,放弃第三方CDN基础结构。 在这篇简短的文章中,我希望这是一个非常简单的文章,我想概述一下“静态地”存储静态文件的缺点以及将它们托管在我的主机上的巨大好处。
我在说什么
对于开发人员来说,单击指向站点和CDN资源上的静态资产(例如库或插件)的链接是很常见的。 一个经典的例子是jQuery。
有很多明显的优点,但是我在本文后面的目标是公开这种方法,并表明缺点更加普遍。
(首先,考虑收益)。
风险:速度下降和故障
在这篇文章中,我不会赘述太多。 我整篇文章都涉及第三方的生存能力以及与延迟和中断相关的风险。 可以肯定地说,如果您有与第三方提供程序相关的任何重要资源,并且提供程序遭受崩溃以及速度下降或中断的困扰,那么这对您来说是不愉快的消息。 您也会受此困扰。
如果您在第三方资源上托管了任何阻止渲染的CSS或同步JS,请继续并将它们立即转移到您自己的基础结构中。 关键资产太宝贵了,无法留在第三方服务器上。
风险:服务终止
这种情况很少发生,但是如果提供者决定需要停止服务怎么办? 这正是Rawgit在2018年10月所做的,到目前为止(在撰写本文时),对GitHub代码的粗略搜索仍然提供了超过一百万个指向该服务的链接,该链接目前正在关闭,并且将近有20,000个现有站点继续参考它。
风险:安全漏洞
要注意的另一件事是简单的信任问题。 如果我们将来自第三方资源的内容带到我们的页面,则我们必须希望我们收到的文件与我们期望收到的文件完全一样,并且文件也与我们期望的完全一样。
想象一下,如果有人可以控制诸如code.jquery.com之类的提供程序并开始提供受破坏的内容或恶意内容,将会带来的危害。 想起来真可怕!
子资源完整性
我们必须向本文到目前为止提到的所有第三方提供者表示敬意,他们正在竭尽全力确保子资源(Subresource Integrity-SRI)的完整性。 SRI是一种机制,提供程序通过该机制提供您期望并打算使用的特定文件的哈希(从技术上讲,是哈希,后跟Base64编码)。 然后,浏览器可以验证您收到的文件正是您所请求的文件。
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script>
再一次,如果您确实需要将静态内容连接到第三方资源,请确保SRI处于活动状态。 您可以自己连接SRI。
推算:网络谈判
我们招致的最大和最紧迫的费用之一是打开新的TCP连接的费用。 我们需要访问的每个新资源都需要打开一个连接,这可能会非常昂贵:DNS解析,TCP握手,TLS协商,所有这些都会起作用,并且随着连接延迟,情况变得更糟。
我将举一个直接从Bootstrap自己的“入门”页面获取的示例。 他们指示用户附加四个文件。
这四个文件位于三个不同的资源上,也就是说,我们需要打开三个TCP连接。 多少钱? 好了,通过相当快速的连接,这些静态文件的内容在侧面为311ms,比将它们放置在您自己的主机上的速度慢了1.65倍。
通过联系三种不同的来源来维修静态资产,我们共同失去了网络批准不必要的805毫秒。
是的,这并没有那么可怕,但是我的客户Trainline发现,将延迟减少300毫秒后,访问者每年需要额外支付800万英镑。 这是一个很容易赚到800万的方法。
只需将资源转移到您的域,我们就完全消除了额外连接的成本。
对于较慢的连接,更长的延迟,情况就更糟了。 对于3G,第三方版本的速度低于1.765s。 我认为这是为了使我们的网站更快。
当延迟较大时,总的网络成本为5.037秒。 什么可以完全避免。
将文件移动到我们自己的基础架构中,可将下载时间从5.4s减少到3.6s。
如果这不是托管您的静态资源的充分理由,那么我不知道还会带来什么。
预连接
自然地,我在这里的演讲的重点是,如果能够在托管服务器上进行发布,则不应在侧面发布任何静态资源。 但是,如果您的双手被束缚住了,则可以使用Resource Hint预连接来主动打开与特定源的TCP连接:此外,将它们部署为HTTP标头会更快。
注意事项 即使您使用预连接,丢失的时间也只会减少一点:您仍然需要打开相应的连接,而且成本也不太合理,尤其是对于慢速连接。
估算:失去优先级
第二种估算是在协议级别进行优化的形式,在将内容划分为域时我们会错过这一优化。 如果使用HTTP / 2,应该执行什么操作,就可以访问优先级。
具有相同TCP连接的所有流(因此资源)都保留优先级,并且浏览器和服务器协同工作以构建所有这些优先级流的依赖关系树,以便我们可以更快地返回关键资源,并可能延迟不太重要的资源的交付。
注意事项 从技术上讲,由于HTTP / 2连接的合并,只要请求共享相同的IP地址,就可以跨不同的域对请求进行优先级排序。
如果我们将资源分布在不同的域中,则必须打开几个唯一的TCP连接。 我们不能交叉引用这些连接的优先级,也就是说,我们失去了以某种经过深思熟虑的方式交付文件的能力。
通过将所有内容托管在一个托管中,我们可以构建更复杂的依赖关系树。 每个线程都有自己的ID,因为它们属于同一棵树。 如果我们从一个域中提供尽可能多的内容,我们可以让HTTP / 2来完成其工作并更充分地对资产进行优先级排序,以期获得更快的响应。
快取
总的来说,静态资源主机在设置长寿命的max-age指令方面似乎做得很好。 这是有道理的,因为版本URL上的静态内容(如上所述)永远不会改变。 这使得执行合理的主动型缓存策略非常安全和合理。
但是,情况并非总是如此,并且通过独立放置资源,您可以开发更多的个性化缓存策略。
误解:跨域缓存
更有趣的是跨域资产缓存的能力。 也就是说,如果许多站点链接到CDN上的同一版本的jQuery,则肯定用户的计算机上已经具有此特定文件。 点对点资源共享之类的东西。 这是使用第三方静态资产提供者的最常见论据之一。
不幸的是,没有公开的证据支持这些主张:没有理由相信这是真的。 相反,保罗·卡尔瓦诺(Paul Calvano)最近的一项研究表明,事实恰恰相反:
CSS资源缓存的使用期限与第一方和第三方网络字体之间存在明显的差距。 95%的第一方字体的使用时间超过1周,而50%的第三方字体的使用时间不到1周。 这为自托管Web字体提供了很好的理由。
通常,似乎第三方内容的缓存比其自身的缓存差。
更重要的是,由于担心隐私滥用,Safari完全禁用了此功能,因此在撰写本文时,共享缓存技术可能不适用于全球16%的用户。
简而言之,尽管从理论上讲这是好的,但是没有证据表明跨域缓存在某种程度上是有效的。
CDN访问
与静态资源提供者联系的另一个广泛好处是,它可能会使用具有CDN功能的强大基础结构:全局分发,可伸缩性,低延迟和高可用性。
因为这是绝对正确的,所以如果您关心性能,则应该从CDN运行自己的内容。 以当前托管价格的水平,没有理由不使用此资源。
换句话说:如果您认为jQuery需要CDN,则所有内容都需要CDN。
在您的主机上托管静态资源
实际上,很少有理由将您的静态资源留在其他人的基础架构中。 可能的利益通常是一个神话,即使没有,妥协也不值得。 从不同来源加载资源要慢得多。 在接下来的几天里,花十分钟审核您的项目,并控制所有第三方静态资源。