10.4 服務終止的範圍:外部引用的種類與持有者
這篇整理一個服務要結束、或失去出資時(只終止一個方案或產品線也適用),要盤點的對象:服務發出去、而且現在存在服務控制範圍以外的引用,以及持有這些引用的人。範圍是提供者(經營服務、發出引用的一方)這一側的終止;自己身為租戶離開別人平台的情形見 10.3 託管形態遷出:資產線盤點與並行期執行(上游公告裡的停止新建、唯讀與關閉各代表什麼,見 10.7 分階段退場:停止新建、唯讀、靜態封存、關閉與公告期),服務仍在、只淘汰一個 API 版本的情形見 11.5 版本策略與 deprecation。
外部引用的定義與種類
外部引用指服務發出去、存放在服務以外的地方、之後會被拿來向服務送出請求、或讓別人的系統依賴服務運作的連結、端點、名稱或身分。服務關閉時,自己系統裡的資料可以刪、程式可以停,外部引用卻還在別人的文件、程式與裝置裡,持有者下一次使用時才會發現服務已經不在。
常見的外部引用有五種,每一種存放的位置不同,持有者能不能自己修改也不同:
| 種類 | 例子 | 存放在哪裡 | 持有者能不能自己改 |
|---|---|---|---|
| 網址 | 短網址、永久連結、<app>.herokuapp.com 這類提供者網域下的子網域、登記在第三方服務的 webhook 回呼網址與 OAuth redirect URI | 文件、貼文、印刷品、書籤、別人網站的連結 | 文件與書籤改得了;印刷品改不了;別人網站上的連結與客戶在第三方服務上登記、指向提供者網域的回呼網址,要等對方改;提供者自己在別的服務登記的 OAuth client 與 webhook,由提供者在退場時刪除 |
| 寫在別人程式或韌體裡的端點 | 行動 app 的 SDK 連線的 API 主機、智慧家庭集線器連線的雲端服務 | 已經安裝在使用者裝置上的 app 與韌體 | 要開發者發新版、使用者更新;韌體要有線上更新管道才改得了 |
| 被嵌入的程式碼網址 | <script src> 指向的公共 CDN 腳本 | 別人網站的 HTML | 網站經營者改得了,但要先知道出了事 |
| 名稱 | 套件名稱與版本、雲端資源的名稱 | 別人的相依性設定檔與 lockfile、DNS 紀錄 | 改得了,但要先知道名稱已經換了主人 |
| 綁在網域上的身分 | 套件維護者帳號用來收重設密碼信的信箱網域 | 套件登錄服務的帳號資料 | 登錄服務能取消過期網域的信箱驗證;帳號擁有者改得了綁定的信箱,但通常不知道網域已經過期 |
表格裡的例子都有實際案例:Google 在 2025 年修正 goo.gl 短網址的停用計畫時寫明這些連結「embedded in countless documents, videos, posts and more」(Google, 2025);Parse 的行動 app SDK 連線的是 api.parse.com,2016 年宣布關閉時,遷移指南把「新版 app 不再依賴 api.parse.com」列為完成條件之一(Parse 遷移指南,Wayback 2016-12);polyfill.io 是十萬個以上網站以 <script> 嵌入的腳本網址(Sansec, 2024)。綁在網域上的身分這一種,提供者是收信網域的擁有者(例如套件維護者),持有者是把這個信箱存成帳號身分的服務(例如套件登錄服務)。
持有者的分類:直接客戶、間接使用者與第三方持有者
外部引用的持有者依「提供者聯絡得到他們嗎」分成三類,這個分類決定服務結束時通知與補救能到達誰:
- 直接客戶:在服務上有帳號、付費或註冊過的人。提供者有他們的信箱,公告與匯出工具都能送到他們手上。Parse 上開發 app 的開發者、Heroku 免費方案的帳號持有人屬於這一類;買了提供者硬體、在服務上有帳號的人(Revolv 集線器、Pebble 手錶的買主)也屬於這一類。
- 間接使用者:直接客戶的產品或內容的使用者。提供者沒有他們的聯絡方式,只能經由直接客戶轉達。Parse 開發者發布的 app 的使用者屬於這一類:他們手機上的舊版 app 仍連線
api.parse.com,要等開發者發新版、自己再更新才會切換。 - 第三方持有者:和提供者沒有任何關係、只是手上有一條引用的人。點擊 goo.gl 短網址的讀者、嵌入 polyfill.io 的網站、相依某個 npm 套件的下游專案都是。提供者手上沒有他們的名單,能觸及他們的只有引用被使用的那一刻(中間頁、回應裡的訊息、套件登錄服務的棄用警告),以及登錄服務、CDN 業者這類中介者。
三類的比例決定退場能做到什麼程度。直接客戶佔多數時,公告、匯出與遷移工具能解決大部分問題;第三方持有者佔多數時,提供者能直接用上的主要是引用被使用的那一刻:goo.gl 在 2024 年 8 月起對部分連結先顯示一頁中間頁,告知連結即將停止運作(Google, 2024);對聯絡不到的第三方持有者來說,點擊短網址、經過中間頁的那一刻,是提供者自己唯一碰得到他們的位置。
API 的消費者還有另外兩種切法:API Consumer Shape 依「會不會回報、改不改得動」分,其中「聯絡不到的外部整合方」大致對應這裡的第三方持有者;Consumer Coordinability 問的「列得出名單、發得出通知」,就是這裡「聯絡得到的程度」。
外部引用在服務結束後的兩種結局:失效與易手
引用也可以在服務結束後繼續運作:提供者以靜態封存維持(10.7 分階段退場:停止新建、唯讀、靜態封存、關閉與公告期),或由接手者承接(10.8 移交:資料匯出、開源與交給社群或封存機構)。沒有人繼續維持時,一條外部引用會走到兩種結局之一,兩者的差別在持有者拿不拿得到失敗的訊號:
- 失效:引用指向的服務或資源不再回應,或回應錯誤(網址失效的情形,英文常稱 link rot)。短網址回 404、API 主機連不上、智慧家庭集線器無法運作。持有者至少拿得到一個失敗的訊號。Nest 在 2016 年關閉 Revolv 集線器的雲端服務時,公告寫的是「The Revolv app won’t open and the hub won’t work」(Revolv 官網,Wayback 2016-02-27)。
- 易手:引用指向的網域、名稱或帳號換了主人,引用照常運作,回應的內容卻由新主人決定。持有者拿到的是一個看起來成功的回應,沒有任何訊號。polyfill.io 的網域與 GitHub 帳號在 2024 年 2 月轉給新的經營者,同年 6 月 Sansec 公布這個網域對行動裝置注入惡意程式碼。網域易手時,沒有任何機制直接通知嵌入它的網站,警告只出現在原作者與 Cloudflare、Fastly 的公開文章裡(Sansec, 2024)。PyPI 的
ctx套件在 2022 年 5 月被接管,成因是擁有者帳號的信箱網域過期,被別人重新註冊之後用來重設密碼(PyPI 事件報告)。
易手的危險在新主人是誰、會做什麼,持有者事先都不知道:持有者原本信任的是提供者,網域到期被陌生人註冊、或在沒有任何公告的情況下賣出之後,回應請求的是持有者沒有選擇過的新主人,而持有者從回應上看不出差別。所以在沒有接手者、也不維持靜態封存的情況下,續約網域但不回應任何內容(讓引用失效),比出售網域或放任它到期更負責任。易手的結果由新主人決定:Insteon 的伺服器在 2022 年 4 月沒有預告就停止,資產在清算中被一群使用者買下,服務因此恢復,但這個結果沒有任何安排保證。事先公告接手者、在條款裡寫明延續範圍的做法稱為公開移交,條件見 10.8 移交:資料匯出、開源與交給社群或封存機構 的〈交給接手的社群或公司〉。網域與名稱的處置見 10.6 命名空間與網域的處置:續約、名稱保留與回收、懸空 DNS。
盤點每一種外部引用的欄位
一種外部引用在服務結束時的下場,由下列幾項性質決定;盤點就是對每一種引用記下這幾項:
- 存放位置:引用寫在哪裡(文件、別人的程式、韌體、DNS 紀錄、相依性設定檔)。
- 持有者的類別:直接客戶、間接使用者還是第三方持有者,以及各佔多少,比較的單位是請求量:請求帶的存取憑證先分出帶直接客戶憑證的請求與沒有憑證的請求(後者多半來自第三方持有者);帶直接客戶憑證的請求,再用客戶端類型或 User-Agent 分出直接客戶自己的後端與間接使用者的裝置(識別符的分層見 11.12 API 消費者用量觀測:契約決策要的觀測維度、消費者身分的識別、欄位級用量與全量或抽樣的成本邊界);客戶端版本的分布則顯示舊版還有多少。
- 持有者能不能自己改:能改的,退場的工作是通知與提供替代;不能改的(印刷品、韌體),只能讓引用本身繼續運作或明確失效。
- 還有沒有人在用:服務有沒有使用紀錄可以回答這個問題。goo.gl 在 2025 年修正停用計畫時,改成只停用「2024 年底沒有活動」的連結,其餘保留,依據的就是點擊紀錄(Google, 2025);npm 判斷一個套件能不能下架時,看的是登錄服務記錄的相依關係與下載數(npm unpublish 政策)。沒有使用紀錄的服務,結束時分不出哪些引用還活著。
- 失效與易手各會造成什麼:持有者拿到錯誤時會發生什麼,引用換了主人時會發生什麼。
- 讓引用繼續運作所需的資料與格式:對照表、套件檔案、設定這類資料,有沒有一份別人讀得懂的匯出格式(見 10.5 退場能力的設計前置:端點間接層、本地運作模式與引用的命名空間 的〈使用紀錄與可交出的資料格式〉)。
- 結束時一定會失去的部分:提供者靠著自己與第三方的契約或授權才提供得了、因此無法交給別人的功能(見 10.5 退場能力的設計前置:端點間接層、本地運作模式與引用的命名空間 的〈依賴第三方契約與授權而無法移交的部分〉)。
到宣布結束時多半已經來不及改的是存放位置(取決於端點間接層與命名空間的選擇)、持有者能不能自己改、還有沒有人在用的紀錄(持有者類別的推估也靠它,要在服務運作期間累積)、讓引用繼續運作所需的資料格式,以及結束時一定會失去的部分,這些是 10.5 退場能力的設計前置:端點間接層、本地運作模式與引用的命名空間 要在上線時處理的;客戶端還收得到更新時,端點間接層與本地運作模式仍可補上,條件寫在 10.5〈客戶端讀取服務位置的端點間接層〉。持有者類別與失效、易手的後果是盤點時記下的事實;結束時還能改變的是引用的去向,見 10.7 分階段退場:停止新建、唯讀、靜態封存、關閉與公告期 與 10.8 移交:資料匯出、開源與交給社群或封存機構。
短網址服務的外部引用
本篇的分類在短網址服務裡全部出現:短網址本身是網址,持有者幾乎全是第三方持有者(0.23 短網址服務的需求定義:自建或購買、保存期限、目的地修改與濫用處理的規格 的〈連結的保存期限與保存承諾〉),服務網域是所有引用共用的命名空間,對照表是讓引用繼續運作所需的全部資料。短網址服務的價值全部在外部引用上,而那些引用的持有者幾乎都聯絡不到。誰在出資維持轉址、出資方式怎麼影響連結的存續,見 短網址的商業模型:訂閱、自架、平台內建與廣告插頁各由誰出資維持轉址。