- 原文地址:Self-Host Your Static Assets
- 原文做者:Harry
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:twang1727
- 校对者:noahziheng, MarchYuanx
有一条为网站提速最方便的捷径,同时也是我建议个人客户们作的第一件事,虽然它有点反常识,就是将全部的静态资源放在本身主机上,而不是用 CDN 或公共的基础设施。在这篇简短而且但愿称得上直白的文章中,我打算列出以 ‘off-site’ 方式托管静态资源的坏处,以及自托管的好处。css
使用托管在公共或者 CDN URL 上的静态资源,好比库或者插件,这种作法对于开发者来讲,十分常见,好比用 jQuery 咱们能够这样作:html
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
复制代码
这么作有许多显而易见的好处,可是我这篇文章的目的是驳倒这些说法,或者是代表这么作成本远大于收益。前端
code.jquery.com
是 StackPath 这个 CDN 来服务的。咱们这样连接资源能够获得 CDN 级别的传输质量,仍是免费的!website-a.com
连接到 https://code.jquery.com/jquery-3.3.1.slim.min.js
,而后用户从那跳转到刚好也连接到 https://code.jquery.com/jquery-3.3.1.slim.min.js
的 website-b.com
,那么文件就已经在用户的缓存里了。这篇文章里我不会讲得太详细,由于我写了一篇完整的文章来讨论第三方服务的恢复力以及相关的减速与宕机风险。能够这样说,若是你有任何重要资源放在第三方服务器上,一旦服务商出现阻塞,甚至直接宕机,那么就糟糕了。你也会遭殃。jquery
若是你用第三方域托管阻塞渲染的 CSS 或同步 JS,如今就把它移回本身的基础设施上。重要的资源不该该放在别人的服务器上。android
虽然并不常见,可是若是服务商决定要中止服务怎么办呢?2018 年十月 Rawgit 关站,然而(在本文写成时)粗略的 Github 代码检索得出,至少一百万个这项已经中止服务的引用,大概 20,000 个正常运行的网站仍在使用它!ios
十分感谢 Paul Calvano 为我提供了 HTTPArchive 上的检索结果。git
另一个须要考虑的问题是可信度。若是咱们将外源内容放在咱们的页面上,咱们就会但愿送达的资源是咱们所指望的,并且只会发挥咱们所指望的做用。github
想象一下若是有人控制了 code.jquery.com
这种服务商并开始提供有漏洞的或恶意的 payload, 那样会形成多大的损失。想都不敢想!web
本文提到的全部服务商值得称道的一点是,它们都应用了子资源完整性 (SRI)。SRI 的机制经过服务商为双方期待使用的文件提供哈希值(准确得讲 Base64 编码的哈希值)来实现。浏览器会检查你收到的文件正是你所请求的那一个。ajax
<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 的入门当作例子。他们指导用户引入如下四个文件:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="..." crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="..." crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="..." crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="..." crossorigin="anonymous"></script>
复制代码
这四个文件由三个不一样的源来托管,因此咱们须要打开三个 TCP 链接。成本是多少呢?
好吧,在还不错的网速上,托管这些静态资源用掉 311ms,或 1.65 倍慢于放置在本身主机上。
链接到托管静态资源的三个不一样的源,咱们在网络协商上总共花费了多余的 805ms。完整测试在此。
OK,不是很糟,可是个人一个客户 Trainline 发现为了下降 300ms 延迟,客户们每一年要多花费 800 万英镑。这么花掉 800 万真是浪费。
单单把资源移到主域,咱们就能够彻底去除多余的链接开支。全文
在高延迟的链接上,状况会糟得多。3G 网络上,外部托管的版本要多花 1.765s 😭,这么作原本不是为了让网站更快吗?!
在高延迟链接上,总联网开支竟达到 5.037s。这彻底能够避免的。全文
将资源移到本身的基础设施上会将加载时间从大约 5.4s 降到仅仅 3.6s。
自托管静态资源时,咱们无需打开更多链接。全文
若是这还不够说服你自托管静态资源,我也没办法了!
preconnect
很天然的,个人主要观点是若是你能本身 host 静态资源你就不该该托管它们。可是,若是这样作不方便,你就能够用 preconnect
资源提示来提早打开相应源的 TCP 链接:
<head>
...
<link rel="preconnect" href="https://code.jquery.com" />
...
</head>
复制代码
把它们看成 HTTP headers 来部署会更好。
注意 即便你实现了 preconnect
,你也只能挽回一小部分浪费掉的时间:你仍是要打开相关链接,特别是那些高延迟的,你不太可能立刻把全部的开支抵消掉。
第二个扣分项以协议层优先处理的形式存在,而这种优先处理在咱们将内容跨域存放是被破坏了。若是你用 HTTP/2(你确实应该用),你就会用到优先处理。同一个 TCP 链接上的全部的流(也就是说资源)都有一个优先级,而浏览器和服务器会协做创建这些优先处理流的依赖树,从而优先递送关键资源,延迟递送不过重要的资源。
想要彻底理解优先处理的好处,Pat Meenan 的文章很好的帮助你入门。
注意 从技术角度讲,因为 HTTP/2 的链接合并,只要有相同的 IP 地址,不一样域上的请求就会被依优先级处理。
若是咱们把资源分置到多个域上,咱们就要打开好几个不一样的 TCP 链接。咱们无法在不一样链接上相互引用那些优先级,因此就会失去以这种深思熟虑、妥善设计的方式传递资源的能力。
比较一下托管和自托管两个版本的 HTTP/2 依赖树:
注意到咱们要对每一个源创建不一样的依赖树了吗?Stream ID 1 和 3 反复出现。
把全部内容放在同一个源下,咱们就能够创建一个惟一的、完整的依赖树。由于全部流都在同一个树里,它们都有惟一的 ID。
有趣的是,奇数 Stream ID 是从客户端起始的,偶数的是被服务器起始的。老实说我历来没见过一个偶数 ID。
若是咱们尽量从一个域提供不少内容,咱们可让 HTTP/2 更全面的作好优先处理,以期更迅捷的响应。
大体上说,静态资源主机很适用于创建长期 max-age
指令。这很天然,由于版本化 URL 上的静态资源(如上)历来不会变。所以使用适度激进的缓存策略是安全合理的。
话虽这么讲,也不是全部状况都适用,并且用自托管资源你能够设计出更有针对性的的缓存策略。
一种更有趣的见解是关于资源跨域缓存的威力的。意思是,若是许多网站连接到同一个 CDN 托管的资源,好比,jQuery,那么用户必定更可能已经在他们的终端上存有相同的文件吗?有点像点对点资源共享。这是支持使用第三方静态资源服务商的最多见理由之一。
不幸的是,彷佛没有任何公开证据来支持这些说法:不能证实事实是这样的。相反的,Paul Calvano 的最新研究暗示了相反的状况:
自托管及第三方托管的 CSS 和网络字体的资源寿命有显著不一样。95% 的自托管字体久于一周而 50% 的第三方字体不及一周。这是对自托管网络字体的强烈支持!
整体上说,第三方内容不如自托管内容缓存比例高。
更重要的是,Safari 彻底去除了这个功能来避免隐私滥用,因此本文写成时共享缓存技术对世界上 16% 的用户是不能应用的。
一句话,虽然理论上很美好,可是无证据代表跨域缓存是有效的。
另一个常常被吹捧的静态资源服务的优势在于,它们想必在具备 CDN 能力的优质基础实施上运行的:全球分布,可伸缩,低延迟,高可用度。
虽说得没错,可是若是你注重性能,你应该已经用 CDN 运行你的内容了。考虑当代托管服务的价格(本网站是用免费的 Cloudflare),不用 CDN 托管资源实在说不过去。
这么说吧:若是你以为你的 jQuery 须要用 CDN,那你所用的东西都须要 CDN。用吧。
实在是没理由把静态资源放在别人的基础设施上。直觉上的优势常常是谎话,即便不是,权衡以后每每就不值得了。从多个源加载资源确实很慢。接下来几天里,花上十分钟来审计一下本身的项目,从新掌控你 off-site 的静态资源吧。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。