[譯] 自託管你的靜態資源

自託管你的靜態資源

有一條爲網站提速最方便的捷徑,同時也是我建議個人客戶們作的第一件事,雖然它有點反常識,就是將全部的靜態資源放在本身主機上,而不是用 CDN 或公共的基礎設施。在這篇簡短而且但願稱得上直白的文章中,我打算列出以 ‘off-site’ 方式託管靜態資源的壞處,以及自託管的好處。css

我在說什麼呢?

使用託管在公共或者 CDN URL 上的靜態資源,好比庫或者插件,這種作法對於開發者來講,十分常見,好比用 jQuery 咱們能夠這樣作:html

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
複製代碼

這麼作有許多顯而易見的好處,可是我這篇文章的目的是駁倒這些說法,或者是代表這麼作成本遠大於收益。前端

  • 方便。像這樣鏈入文件特別省事,複製粘貼一行 HTML,搞定。真簡單。
  • 咱們接入了 CDNcode.jquery.comStackPath 這個 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.jswebsite-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 能力的優質基礎實施上運行的:全球分佈,可伸縮,低延遲,高可用度。

雖說得沒錯,可是若是你注重性能,你應該已經用 CDN 運行你的內容了。考慮當代託管服務的價格(本網站是用免費的 Cloudflare),不用 CDN 託管資源實在說不過去。

這麼說吧:若是你以爲你的 jQuery 須要用 CDN,那你所用的東西都須要 CDN。用吧。

自託管資源

實在是沒理由把靜態資源放在別人的基礎設施上。直覺上的優勢常常是謊話,即便不是,權衡以後每每就不值得了。從多個源加載資源確實很慢。接下來幾天裏,花上十分鐘來審計一下本身的項目,從新掌控你 off-site 的靜態資源吧。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索