事實
網路基礎設施 · 軟體工程 · 資訊安全 · 工程簡報2026 年 6 月切換 · 紀錄至 2026 年 9 月
Cloudflare 把 cdnjs 搬到自家開發者平台
每日 90 億次請求,搬家時一個檔案都沒有重建
2026 年 6 月 23 日起,cdnjs——大約每九個網站就有一個在用的免費 CDN——全面改在 Cloudflare 自家的開發者平台上運行;7 月 30 日 Cloudflare 發表了整個過程。搬遷是標題,「回滾」才是心得:先前一次嘗試把舊有檔案重新產生,每個檔案都得到不同的完整性雜湊;對任何把雜湊寫死在網頁裡的人來說,那不是差異,是一片空白。所以整份目錄改為逐位元組原樣複製。切換三週後,同一個教訓從另一頭回來——新的發佈機器人被發現會把它解開的每個檔案最後一個位元組丟掉。
- 2026 年 6 月 23 日全面上線開發者平台;37 天後才公開
- 9.18 bn每日請求數,依 cdnjs 自己的月報以截至 2026 年 7 月的十二個月平均;單看 7 月是 74 億
- 98.6%快取命中率(Cloudflare 自述)——每日仍約有 1.26 億次請求越過快取(本站推算)
- 1 個位元組新發佈機器人解開的每個檔案末尾被截掉的長度,直到 2026 年 7 月 17 日修正
| 可信度 | 主張內容 |
|---|---|
| 有文件佐證 | 瀏覽器拿到 integrity="sha384-…" 之後會對收到的內容計算雜湊,只要沒有一個相符,就拒絕載入該資源並回傳網路錯誤。沒有降級模式。這正是重新產生的檔案會造成服務中斷、而非外觀差異的原因。 |
| 有文件佐證 | 切換之前有兩道平台上限被提高,Cloudflare 的更新日誌替兩者都標了日期。2026 年 2 月 11 日,付費方案每次呼叫的子請求上限由 1,000 改為預設 10,000,可設定至 1,000 萬。2026 年 3 月 3 日,Workflows 的步驟上限由 1,024 提高到 10,000,可設定至 25,000。 |
| 有文件佐證 | 切換三週後,一位使用者回報 cdnjs 上 Font Awesome 7.3.0 的字型無法解碼。負責搬遷的工程師追查到新發佈機器人所用的 tar 解析器:它會把每個檔案項目的最後一個位元組拿掉。多數檔案以換行結尾,因此沒事;但字型、WebAssembly、SVG、最小化 CSS 與 JSON 都壞了。Font Awesome 7.1.0 至 7.3.0 於 7 月 17 日修正並重新發佈。 |
| 有文件佐證 | 曾經是 cdnjs 唯一真實來源的 GitHub 倉庫,最後一次自動提交是 2025 年 9 月 30 日。2026 年 9 月 3 日,倉庫加上說明:它「因為變得太大,已不再更新」,cdnjs 現在由一個 R2 儲存桶提供。 |
| 見於專案自己的報告 | 流量與觸及率。cdnjs 以 Cloudflare 提供的資料編製的月報顯示,2025 年 6 月至 2026 年 4 月每日請求數在 90 億到 100 億之間,2026 年 5、6、7 月則為 86 億、85 億與74 億。Cloudflare 文章自己連結的 W3Techs 量得 2026 年 9 月 cdnjs 出現在全部網站的 11.3%——即可辨認其 JavaScript CDN 的網站中的 48.0%。 |
| 營運方確認,此處無法驗證 | 切換日期;每秒 108,000 次請求;330 個以上的資料中心;98.6% 快取命中率;新的架構。以及一次被回滾的先前搬遷嘗試:重新處理舊套件所得的檔案內容正確、位元組卻不相同,完整性雜湊因此改變;之後整份目錄改為「原樣」從 KV 複製到 R2。 |
| 主張,且被專案自己的紀錄所削弱 | cdnjs 上每個檔案都有 SRI 雜湊——這句話說完三句後,作者承認 Cloudflare 仍在確認已存的雜湊是否與實際相符。切換前比對期間寫下的一個拉取請求還補充:新舊兩套雜湊流程都是「盡力而為」,無法計算雜湊的檔案會被悄悄略過。 |
時序
一路走來 十五年、一步無法定年,以及文章發表之後的事
- 2011 年誕生,隨後搬到 Cloudflare。Ryan Kirkman 與 Thomas Davis 於年初在 Amazon CloudFront 上建立 CDNJS;成本與難以支援 HTTPS 迫使他們離開,6 月改在 Cloudflare 上線,免費代管。
- 2019 年底Cloudflare 接手維護整個倉庫,起因是一個社群機器人停擺。當時倉庫不含歷史紀錄就有 182 GB。
- 2020 年 4 月來源伺服器斷線。一座存放 cdnjs 主要來源伺服器的核心資料中心離線約四小時;Cloudflare 的快取把影響限縮在未快取的檔案。Cloudflare 事後稱之為第一次警鐘。
- 2020 年 9 月服務端搬了,發佈端沒有。檔案改由 Workers 與 KV 提供,並預先以 Brotli 與 gzip 壓縮。監看 npm 與 GitHub 的流程仍留在 Google Cloud。
- 2021 年 4 月至 6 月發佈機器人被一位研究者攻破。一個精心製作的 npm 套件讓 RyotaK 能在自動更新伺服器上執行程式碼。Cloudflare 一小時內撤銷所有憑證,一天內推出修正,並於 6 月 3 日完成流程重新設計;它表示沒有任何既有函式庫遭到修改。
- 日期不明那次被回滾的嘗試。舊套件被重新處理並直接寫入 R2;結果與 KV 原本提供的內容在位元組上並不相符,完整性雜湊因此不同,變更遭到撤回。【沒有任何來源給出它的日期。】
- 2025 年 9 月 30 日GitHub 映本停止更新。曾是 cdnjs 唯一真實來源的倉庫收到最後一次自動提交。
- 2026 年 2 月 11 日子請求。付費方案預設值由每次呼叫 1,000 提高到 10,000,可設定至 1,000 萬。
- 2026 年 3 月 3 日Workflow 步驟。1,024 改為預設 10,000,可設定至 25,000。
- 2026 年 6 月 11 日至 17 日切換前的影子比對。新的中繼資料 worker 被設定為以部分真實流量,將自己的回應與舊來源比對;規則是雜湊比以前多算是涵蓋增加,比以前少算是涵蓋流失。
- 2026 年 6 月 23 日cdnjs 全面在開發者平台上運行。R2 成為檔案內容唯一的真實來源,KV 只保留中繼資料。
- 2026 年 7 月 13 日至 17 日消失的位元組。Font Awesome 字型損壞被回報,追查到新機器人的 tar 解析器,四天內修正並重新發佈。
- 2026 年 7 月 30 日Cloudflare 發表過程,距離切換 37 天。InfoQ 於 8 月 14 日報導。
- 2026 年 8 月 25 日至 29 日映本與網站。8 月 25 日,首批映本營運者取得 R2 目錄的唯讀存取權;8 月 29 日,cdnjs.com 改由原本就提供 API 的 Worker 提供。
- 2026 年 9 月 3 日GitHub 倉庫自己說明了。加上說明:不再更新、體積太大、改由 R2 提供。
有一步沒有日期,而那正是重要的一步
此處其他每一項都至少精確到月份。唯獨那次被回滾的嘗試完全沒有日期——沒有月份,也沒有年份——因此無法誠實地排進時序。這裡把它列為日期不明,而不是猜一個。切換前後自動更新何時暫停,紀錄裡同樣沒有;只知道 7 月 13 日之前已重新啟用。
論點
Cloudflare 想論證什麼 自家產品自己用,以及全篇指向的那句話
原文自己的用詞是 dogfooding(自家產品自己用),其論證是一個三段論:cdnjs 規模龐大,cdnjs 現在跑在任何人都租得到的同一套元件上,所以那套元件撐得住你要做的東西——「它大概撐得住你正在做的任何東西」。兩半值得拆開看。證據是真的:兩道平台上限因為 cdnjs 撞到而被提高,Cloudflare 的更新日誌把兩者分別標在 2026 年 2 月與 3 月,而且適用於每一位付費客戶。只是它比原文聽起來的要小。原文——以及之後的 InfoQ——說子請求「現在最高可達 1,000 萬」;更新日誌寫的是付費方案預設值變成 10,000,1,000 萬則是客戶必須自行設定的上限。預設是十倍,不是一萬倍。推論則是推銷,原文也沒有假裝不是。它明講這不是效能問題——「我們搬遷不是因為 cdnjs 慢」——並稱舊架構有 98% 快取命中率,而且照它的說法沒有中斷過。抱怨在於:要改任何東西,就得跨 Google Cloud 函式、一台虛擬機與 Cloudflare 協調部署;而且半途失敗無從察覺:一個版本可能寫進了 KV,卻悄悄沒進到 GitHub 倉庫,然後正常服務好幾週,直到有人發現兩邊已經分岔。
- 26個 Cloud Function 只為了檢查 npm——每個字母一個,各有各的部署與日誌。
- 274條手工維護的
.gitignore規則,用來擋掉損壞或版號古怪的釋出——原文自己的說法是「一座有文件記載的墳場」。 - 10×Workers 子請求預設上限的提升幅度,由 1,000 到 10,000——另有可設定至 1,000 萬的上限,原文的標題數字就是從那裡來的。
補充
機制,從兩頭看 為什麼重新產生的檔案是一片空白,少一個位元組也是
子資源完整性
瀏覽器是拒絕,不是降級
- 網頁可以把雜湊寫死:
<script integrity="sha384-…">。 - 瀏覽器對收到的內容計算雜湊並比對。不符時回傳網路錯誤,該腳本永遠不會執行。跨來源時,這項檢查還需要 CORS。
- 來源:MDN。這正是第一次搬遷嘗試必須撤回的全部原因。
- 網頁可以把雜湊寫死:
決定性
重建得到的是正確的位元組,不是相同的位元組
- 壓縮與最小化工具在不同版本間並非完全決定性,幾年後重跑,得到的是「正確」但不「相同」的輸出。
- 位元組不同就代表雜湊不同,而雜湊不同就代表每個寫死了舊雜湊的網頁都會壞掉。
- 通則:以內容定址的儲存無法重建,只能複製。
消失的位元組
同一個教訓,從另一頭回來
- 在維護者自己的議題追蹤裡,負責搬遷的工程師寫道,新機器人的 tar 解析器「會拿掉每個檔案項目的最後一個位元組」——那個位元組是換行時無害,在字型裡就是致命的。
- 修正的方法是以原本的版本網址重新發佈 Font Awesome 7.1.0 至 7.3.0。
- 本站解讀:這正是那次回滾所說、不該發生在已流通檔案上的事,只因檔案本身錯了而不得不做。回滾與那個位元組是同一個教訓的兩面——CDN 第一次發佈的位元組,就是它得一直背著的位元組。
仍然未知的部分
目前有多少已存的雜湊是錯的,又有多少從未產生
- Cloudflare 說它仍在讓已存的雜湊與實際相符,原因是「舊系統的錯誤」。
- 一個 2026 年 6 月的拉取請求補充:兩套雜湊流程都會略過無法計算雜湊的檔案,並把新流程回傳較多雜湊視為涵蓋增加。
- 兩者都沒有給出規模。只要某個被人寫死的檔案雜湊是錯的,某處就有一個壞掉的網頁。
搬遷的前後 安全紀錄、數字,以及專案接下來做了什麼
發佈流程才是值得守護的部分,而且有前例。原文說,汰除舊流程就少了一大堆要守護的東西——函式、虛擬機、儲存桶、服務帳戶金鑰。2021 年 4 月,研究者 RyotaK 示範了這一面為何重要:一個帶有精心製作之符號連結的 npm 套件,讓自動更新伺服器執行他的程式碼並洩漏憑證。Cloudflare 一小時內撤銷憑證、讓服務下線,並於當年 6 月完成流程重新設計;它表示沒有任何既有函式庫遭到竄改。那是五年前已修正的事,不是 2026 年原文提到、卻未具名的那些漏洞。以一年平均來看,數字禁得起檢驗;一個月一個月看就沒那麼漂亮。原文的觸及率數字來自 W3Techs,原文自己就附了連結:2026 年 9 月為全部網站的 11.3%,原文則寫「約 12%」。它的「每日 90 億次」與 cdnjs 自己的月報以一年平均來看相符——截至 2026 年 7 月的十二個月平均 91.8 億——但單看 7 月是 74 億,是讀過的十四個月中最低的一個月。沒有任何來源給出原因,這裡也不提供。文章發表之後,搬遷仍在繼續。映本營運者——其中包括一個服務中國大陸的映本和一個完整性監控服務——自 8 月 25 日起取得 R2 目錄的唯讀存取權;cdnjs.com 網站於 8 月 29 日移到 API 所用的 Worker 上;GitHub 倉庫如今也明白寫著它已不再更新。
- 7.4 bn2026 年 7 月每日請求數,十二個月平均則為 91.8 億——沒有來源說明原因。
- 11.3%的網站使用 cdnjs(W3Techs,2026 年 9 月)——據此推算,約 23.5% 的網站使用某個 JavaScript CDN(本站推算)。
| 舊 | 新 | 實際改變了什麼 |
|---|---|---|
| Workers KV + 一個 GitHub 倉庫 | R2 作為唯一真實來源 | 先前兩個儲存都不是權威,一旦分岔就沒有乾淨的辦法對齊。GitHub 那份其實在切換前將近九個月就不再收到檔案了。映本現在透過 R2 的 S3 介面同步,唯讀憑證依申請發放。 |
| 一連串由儲存桶事件觸發的 Cloud Function | Workflows,搭配 Queues 與一個 Durable Object 計數器 | 儲存原本兼作訊息佇列——沒有死信佇列、看不到積壓、失敗也無法乾淨重跑。Workflows 會保留每一步的狀態,逾時是接續而不是重來。 |
| 邊緣後方的一台裸機來源 | 快取 → R2 → DigitalOcean Spaces | DigitalOcean 鏡像整份儲存:架構上是災難備援副本,運作上是即時備援。截至原文發表時,在 GitHub 回填完成之前,鏈路上仍有一台 Cloudflare 代管的來源;之後沒有任何來源說明是否已完成。 |
| 一個獨立的靜態網站 | 與 API 同一個 Worker | 2026 年 8 月 29 日,cdnjs.com 改為由提供 API 的那個 Worker 產生頁面——文章發表之後,又一塊搬上了同一個平台。 |
結論
可以帶走什麼 一個可以套用的心得,以及哪些不必抓太緊
複製位元組,不要重建——而且第一次就要做對
這一段可以套用到跟 CDN 毫無關係的系統上。只要下游有人把你的輸出雜湊寫死了,那份輸出就不再是你能重新產生的東西——工具鏈會前進,位元組會不同,而「正確」並不足夠。Cloudflare 是試過並回滾之後學到的,而且把它寫了出來。7 月那個消失的位元組,是同一條規則從另一頭看:發佈錯了的檔案,只能靠打破「它永不改變」的承諾來修正。
在標題的意義上完成了,實務上仍在推進
cdnjs 確實跑在開發者平台上。在這個事實周圍,紀錄顯示:一條暫停後又重啟的更新流程、上線三週時發現並修正的缺陷、兩個月後才搬的網站、改從 R2 同步的映本,以及原文說回填完成後就會退役的一台來源。這些都沒有推翻標題;它們正是這種規模的搬遷實際的樣子。
數字要抓鬆一點,安全性主張要抓得最鬆
「每日 90 億次」當作一年平均是公允的,放在文章發表的那個月就偏寬了;上限提升預設是十倍,只有主動設定的客戶才是一萬倍。這些是紮實的部分。最該抓鬆的一句,是汰除舊流程「關閉了近期所有已開立的 cdnjs 漏洞」——沒有數量、沒有編號、沒有嚴重程度,而這篇文章其他地方精確到個位數。
無法查證的部分
傳言——Cloudflare 自述:汰除舊流程「關閉了近期所有已開立的 cdnjs 漏洞」。沒有數量、編號或日期,專案主要倉庫也沒有發布任何安全公告。
傳言——Cloudflare:GitHub 倉庫超過 1.1 TB 的封裝儲存量,GitHub 的封存服務因此拒絕為它產生下載檔。GitHub 自己的倉庫紀錄給出的大小約 70 GB,但它並未定義這項度量;沒有任何資料能讓兩者對得上。
傳言——Cloudflare:2020 至 2026 年使用的架構從未中斷。無論正反,都找不到專門針對 cdnjs 的事故紀錄。
傳言——Cloudflare:語言模型之所以愛用 cdnjs,是因為訓練資料裡滿是它。這是作為解釋提出,並沒有測量。
核心要點與來源
- Simona Badoiu,〈Dogfooding at scale: migrating cdnjs to Cloudflare’s Developer Platform〉,The Cloudflare Blog,2026 年 7 月 30 日
- W3Techs,〈Usage statistics and market share of CDNJS for websites〉,2026 年 9 月
- Cloudflare 更新日誌,〈Workers are no longer limited to 1000 subrequests〉,2026 年 2 月 11 日
- 〈Workflows step limit increased to 25,000 steps per instance〉,2026 年 3 月 3 日
- Matthew Prince,〈CDNJS: Community Moderated Javascript Libraries + CloudFlare〉,2011 年 6 月 16 日
- Zack Bloom,〈An Update on CDNJS〉,2019 年 12 月 19 日
- Tyler Caslin,〈Migrating cdnjs to serverless with Workers KV〉,2020 年 9 月 10 日
- Jonathan Ganz、Thomas Calderon 與 Sven Sauleau,〈Cloudflare’s Handling of an RCE Vulnerability in cdnjs〉,2021 年 7 月 24 日——皆刊於 The Cloudflare Blog
- RyotaK,〈Remote code execution in cdnjs of Cloudflare〉,2021 年 7 月 16 日
- MDN Web Docs,〈Subresource Integrity〉,Mozilla
- Leela Kumili,〈Cloudflare Migrates JavaScript CDN Serving 9B Requests a Day to Its Developer Platform〉,InfoQ,2026 年 8 月 14 日
- cdnjs 於 GitHub:每月使用報告(cf-stats),2025 年 6 月至 2026 年 7 月
- metadata-worker 拉取請求 6 與 7,2026 年 6 月
- cdnjs 議題 14305、14307 與 14309,2026 年 7 至 8 月
- api-server 拉取請求 279,2026 年 8 月 29 日
- cdnjs/cdnjs 倉庫說明檔及其 GitHub 倉庫紀錄,2026 年 9 月。所有來源皆於 2026 年 9 月 28 日全文閱讀。