「做一個短網址服務」這項需求在交給工程實作之前,有幾個決定要先定案。多數決定的答案從商業模型推出,少數由使用情境決定,每一項又落到實作的某一個位置:商業模型的分類在 短網址的商業模型:訂閱、自架、平台內建與廣告插頁各由誰出資維持轉址,實作的取捨在 0.24 短網址服務的實作:短碼生成、對照表儲存、轉址快取與點擊紀錄(下文稱實作篇),本篇處理兩者之間的轉換。

短網址的核心功能——收到一個短碼、轉往它對應的長網址——用幾十行程式就寫得出來,所以這個需求的難度集中在功能周圍的承諾:連結會活多久、點擊有沒有被記下來、被人拿去散布釣魚網址時誰處理。這些承諾在需求文件裡常常沒有被寫出來,而工程實作的每一個關鍵選擇都依賴它們。

自建或購買:自建成立的理由與自建之後的長期成本

要不要自建要最先定案,因為買現成服務時,轉址、快取與濫用處理的多數決定由供應商做;買方仍然要決定三件事:用不用自己的品牌網域、能不能定期匯出短碼對照表、降級或停止付費之後既有連結還轉不轉址。這三項決定換業者或停止付費時,已發出的連結還能不能用,判讀見短網址的商業模型的〈訂閱型業者的收入重心與連結承諾的預警訊號〉一節與 0.21 交付形態選型 的可遷出保險。現成的短網址 SaaS 提供建立、轉址、點擊分析、自訂網域與 API,而且承擔了濫用處理與長期營運,判斷方式和其他能力相同(見 0.22 能力級買 vs 建:feature-as-a-service 與 BaaS bundle 選型):差異化不在這項能力上,就先買。這一項的依據來自商業模型:短網址在產品裡承擔什麼角色,決定它值不值得自己營運。

行銷團隊要為活動產生可追蹤的連結、客服要在簡訊裡放短網址,這類需求是 SaaS 的標準用途,自建換來的只有營運負擔。自建成立的理由通常落在下列幾種之一:

  • 短網址是產品本身的一部分:社群平台把使用者貼文裡的每一個外部連結改寫成自己網域的短網址,目的是在轉址當下掃描惡意網址、記錄哪一則貼文帶出了多少點擊。這些資料是平台自己的產品資料,交給第三方就失去了。
  • 點擊資料不能離開組織:連結的目的地或點擊者的資訊受法規或合約限制,不能存放在外部服務。例如醫療院所在就診提醒簡訊裡放的連結,目的地網址帶著病患的預約編號。
  • 需要 SaaS 不提供的轉址邏輯:例如依裝置或地區導向不同目的地、深層連結到 App。
  • 用量大到按量計價不划算:SaaS 多半依連結數或點擊數分級收費,用量到某個規模之後,自建的營運成本低於訂閱費。這個交叉點要拿實際的報價與預估用量算,不同供應商的級距差異很大。

自建也有不寫程式的做法:在自己的主機上部署開源的短網址專案(MIT 授權的 YOURLS、AGPLv3 的 Dub)。「點擊資料不能離開組織」與「用量大到按量計價不划算」這兩個理由,多數用自架就能滿足:點擊資料留在組織內,費用從訂閱費換成營運責任。只有連自架版本的資料模型或擴充點都不夠時,才走實作篇的整套實作路線;交付形態的完整光譜見 0.21 交付形態選型。

不論自架或自寫,自建之後的成本都集中在三項長期承諾:連結的永久營運、濫用處理的人力與流程、點擊資料的隱私責任,轉址程式本身佔的比例很小。估算自建成本時把這幾項算進去,交叉點會往後移。

決定自建的有兩種營運者:自用的組織(為自己的簡訊、行銷或內部系統產生連結),以及把短網址當產品賣給別人的業者。下文的點擊分析收費與自訂網域兩節以業者為主角;自用的組織讀到「客戶」時,對應的是組織內各個建立連結的部門。

點擊資料的地位:付費功能或內部參考,以及對應的規格

短網址服務每一次轉址都能記下一筆點擊:時間、來源、大致的地理位置、裝置類型。這筆資料在商業模型裡的位置決定了一連串規格。

點擊分析是付費功能時,點擊資料就是產品。客戶付費買的是準確的數字,少算等於少交付,所以點擊要在很短的時間窗內回到服務被記錄,事件不能遺失,報表要能回答客戶會問的維度(哪一個活動、哪一個國家、哪一天)。點擊統計只是內部參考時,它是副產品,可以接受取樣、可以接受伺服器故障期間遺失還沒送出的點擊事件。

這一項決定在實作上落到兩個位置。瀏覽器預設會把「永久移動」的轉址長期保存,之後的重複點擊直接在本機轉走、不再送到服務,也就記不到;所以轉址結果能被瀏覽器保存多久要有一個很短的上限,狀態碼與快取標頭怎麼選見實作篇的〈轉址回應的快取標頭與瀏覽器保存回應的時間〉。點擊事件則要寫進不會遺失的佇列,而不是記憶體裡的緩衝。兩者的代價都是服務要承擔幾乎每一次點擊的負載。

點擊資料裡的 IP 位址與裝置資訊屬於個人資料,所以報表的粒度(國家、城市還是精確位置)、保存期限、客戶能不能下載原始資料,同時也是隱私責任的大小。報表只需要國家時,原始 IP 在彙總後就可以刪除,隱私責任隨之縮小。

連結的保存期限與保存承諾

短網址一旦發出去,就被印在海報上、寫進書裡、存進別人的書籤。持有連結的人只有短網址,沒有原本的長網址,服務停止回應的那一天,這些連結就全部失效,而持有連結的人自己沒有任何修復的途徑。所以「連結保存多久」是對所有持有連結的人做的承諾,這些人大多不是服務的客戶,也從來沒有同意過任何條款。

保存承諾有三個問題沒有預設答案,每一個答案都直接改變持有連結的人點下去之後看到什麼:

這項承諾能維持多久,取決於由哪一種商業模型出資。由付費客戶出資的服務,連結的存續與營收綁在一起;作為大公司附屬工具、沒有獨立營收的短網址服務,母公司不再需要它時就可能關閉,實際的關站案例見短網址的商業模型的〈連結永久性:各出資方式下連結的存續條件〉一節。

目的地修改的功能需求與風險

允許建立者在連結發出之後修改目的地,是一項有明確需求的功能。QR code 印在包裝、名片或店面上之後就無法更換,背後的網址能改,同一張印刷品就能在活動結束後改導到新頁面;連結的目的地網站搬家時,修改短網址的目的地就能讓舊連結繼續有效。這一項由使用情境決定:印刷品印出之後無法更換,目的地網站也會搬家。

同一項功能也是風險。收到連結的人信任它,是基於分享當下它指向的內容;目的地可以修改時,建立者可以先放一個正常頁面讓連結被廣泛分享,再改成釣魚頁面。所以允許修改的同時,要一起定案三件事:修改後要不要重新做惡意網址檢查、修改紀錄要不要保留、要不要讓點擊者能預覽目前的目的地;少了任何一件,修改目的地就成了先騙取信任再換成釣魚頁的工具。

這一項決定在實作上影響快取。目的地不會變時,轉址結果可以被瀏覽器、CDN 與應用程式快取很久;目的地能改時,每一層快取都要能在修改後失效,否則有人會被送到舊的目的地。教材裡幾篇以短網址為例的盤點與分析,用的是允許修改目的地、撤回在幾分鐘內生效的設定,見 Backend 範例系統 的〈短網址服務〉。

建立者的範圍與濫用處理

短網址把目的地藏在一個看不出內容的網址後面,這個性質被釣魚與惡意軟體散布者大量利用,以廣告插頁付錢給建立者的服務被濫用得最嚴重(見短網址的商業模型的〈廣告插頁:廣告抽成的差價與濫用風險〉一節)。開放越多人建立連結,濫用越難追溯到人;而服務的網域被大量用來散布惡意連結之後,郵件過濾器與瀏覽器可能把整個網域列為可疑,所有正常連結跟著被擋下。

建立者的範圍大致有下列幾種,濫用處理的投入差距很大:

  • 只限組織內部使用者:建立者可追溯,濫用風險接近組織內部的資安問題。
  • 開放註冊,需要驗證帳號:濫用可以追溯到帳號,處理方式是停權與停用連結,需要一個檢舉管道與處理流程。
  • 匿名建立:濫用無法追溯到人,只能靠速率限制、建立時的惡意網址檢查與事後的停用。
  • 經由 API 代客戶的使用者建立:客戶把建立功能開放給自己的使用者,濫用只能追溯到客戶的 API 金鑰,處理方式是要求客戶自己做使用者驗證、對每把金鑰設速率上限,並能整批停用某把金鑰建立的連結。

開放對外建立時,濫用處理有幾個問題沒有預設答案:檢舉從哪裡進來、誰負責判定、確認惡意之後多久之內連結要失效、被停用的連結點下去顯示什麼、執法或法律請求由誰回應。其中失效時限會直接限制工程實作的快取時間,因為已被瀏覽器或 CDN 快取的轉址,在快取到期之前不會回來查詢連結是否已被停用;所以這個數字屬於需求,不屬於技術選擇。檢舉與詐騙回報多半先進到客服,客服怎麼判斷一則回報要當場答覆、開單還是立即呼叫值班,見 8.24 客服回報的處理。

短碼的可猜測性與私密連結

建立者會把什麼樣的網址拿來縮短,影響短碼本身的規格。這一項由使用情境決定,與收入模型無關。雲端文件的分享連結、私人行事曆的訂閱網址、密碼重設連結,都屬於「知道網址就能存取」的連結。這類連結被縮短之後,短碼能不能被猜到,就成了連結背後的文件、行事曆或帳號能不能被外人取得的問題。

服務預期承載這類連結時,短碼必須不可預測:工程實作就不能把遞增序號直接編碼成短碼(序號加一就得到別人的連結),要保留序號,編碼前得先用帶金鑰的加密把它打散,否則改用隨機產生。服務只用於公開的行銷頁面時,這項限制可以放寬,換取更短的短碼。

自訂網域與網域名聲的隔離

所有連結共用服務自己的短網域,是最簡單的做法,代價是名聲共用:一個客戶的濫用行為會讓所有客戶的連結一起被封鎖清單擋下。讓客戶使用自己的網域(例如把 go.example.com 指到服務),點擊的人看得到品牌,信任度較高,該客戶的連結名聲也和其他客戶分開。多數業者的方案頁稱這項功能為「自訂網域」,商業模型那篇從客戶的角度稱它「品牌網域」,兩者指同一件事。

自訂網域在商業上常是付費方案的區分點,在工程上帶來網域所有權驗證、每個網域的 TLS 憑證簽發與更新,以及「同一個短碼在不同網域是不同連結」的資料模型變化。要不要支援、由哪個方案提供,以及客戶停止付費之後網域上的連結怎麼處理,三個答案合起來決定自訂網域對客戶是保險還是另一種綁定。

建立路徑與轉址路徑的可用性分級

短網址服務對外有兩條路徑:建立路徑接收長網址、產生短碼,轉址路徑收到短網址的請求後轉往長網址。兩條路徑對可用性的要求不同,這一項同樣由使用情境決定。建立路徑暫停時,受影響的是正在建立連結的少數人,他們可以稍後再試;轉址路徑暫停時,所有已經發出去的連結同時失效,影響的是持有連結的所有人,而他們沒有替代方案。

這個排序的前提是建立是一個獨立的操作,由使用者主動送出、失敗可以重試。建立由系統在另一條寫入路徑裡自動觸發時(社群平台在發文當下改寫連結、通知系統在送出簡訊之前產生連結),建立路徑暫停就擋住整批發文或訊息,它的可用性與延遲就是那條路徑的一部分,目標要跟著那條路徑訂;這類服務也常讓發送端在建立失敗時退回使用長網址,或在內容發出後仍可改寫的情境(例如貼文),把建立改成非同步、先用原網址發出再補上短網址。

所以可用性目標要分開訂(見 SLI / SLO):轉址路徑的目標要高於建立路徑,點擊統計與報表的目標可以更低,而且統計的故障不能拖垮轉址(見 degradation)。尖峰的估計也以轉址為主:共用連結的尖峰來自單一連結被大量轉發,和每天建立多少連結關係不大;替每位收件人各產生一條的連結,尖峰則跟著每一批發送的收件人數走。客戶若有大型活動(例如電視廣告上出現的短網址),事先通知的管道讓服務能在尖峰之前擴容;沒有預告的爆紅見 0.25 短網址服務的瞬時大流量:爆紅連結、建立路徑的機器人濫用與轉址路徑的攻擊 的〈爆紅連結的負載落點:CDN、程序內快取與對照表〉。

互相限制的需求決定

本篇各節的決定各自有答案,組合起來有幾組會互相限制,需求定案前要一起檢查:

  • 開放建立與可被長期快取的轉址不相容:開放建立就必須能停用惡意連結(連結會到期或可被刪除時也是同一個限制),而沒有快取上限的轉址會被瀏覽器保存,已經點過這條連結的瀏覽器存著舊的轉址,停用對它們無效。所以只要開放對外建立,轉址結果就不能被瀏覽器無限期保存;這個快取上限同時決定停用最慢多久生效,以及有多少重複點擊不被計入。
  • 承載私密連結與永久保存互相衝突:短網址就是存取憑證,永久保存等於存取憑證不過期。預期承載這類連結的服務,到期時間要依連結背後的資料來訂,而不是依儲存成本;到期時要把對照表裡的長網址一起清空,因為長網址才是那份資料的存取憑證;點擊紀錄或修改歷史若存了長網址,保存期限要跟著縮短。
  • 目的地可修改與永久保存疊加時,風險隨時間累積:連結活得越久,被改成惡意目的地的機會越多,修改後的重新檢查與修改紀錄要隨保存期限一起設計。
  • 點擊分析的粒度與隱私責任同向增加:報表要的維度越細,保存的個人資料越多,保存期限與刪除流程要隨報表規格一起定。
  • 自訂網域讓客戶在服務終止時接手自己的連結:客戶的網域在客戶手上,服務終止時客戶可以把網域指到別處、在新服務上重建連結,前提是短碼對照表能匯出。這一點也是自訂網域在保存承諾上的優勢。

這些決定定案之後,每一項落到實作的哪一個位置、換掉其中一項時實作要改哪裡,列在實作篇的〈各項需求決定對應的實作位置〉一節。