 TUS 協(xié)議的可恢復(fù)上傳實戰(zhàn)指南)
使用 Supabase Storage 與 Uppy 實現(xiàn) TUS 協(xié)議的可恢復(fù)上傳實戰(zhàn)指南【免費(fèi)下載鏈接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.項目地址: https://gitcode.com/GitHub_Trending/supa/supabase導(dǎo)讀本文圍繞 examples/storage/resumable-upload-uppy 這份官方示例展開講解如何用 Uppy瀏覽器端上傳組件庫通過 TUS 協(xié)議向 Supabase Storage 進(jìn)行可恢復(fù)斷點(diǎn)續(xù)傳上傳。讀完后你將掌握為什么要用可恢復(fù)上傳、如何在控制臺或 SQL 中準(zhǔn)備存儲桶與公網(wǎng)寫入策略、如何用四個核心變量配置前端、以及 TUS 分塊上傳背后的斷點(diǎn)續(xù)傳與并發(fā)沖突機(jī)制。倉庫中還包含配套的 resumable-upload-signed-uppy簽名 URL 變體與官方文檔 apps/docs/content/guides/storage/uploads/resumable-uploads.mdx可作為對照與深化閱讀。為什么選擇可恢復(fù)上傳在動手前先判斷你的場景是否真的需要可恢復(fù)上傳。根據(jù) Supabase 官方文檔 apps/docs/content/guides/storage/uploads/resumable-uploads.mdx當(dāng)滿足以下任一條件時推薦使用 resumable upload 方案上傳大文件文件體積可能超過 6MB網(wǎng)絡(luò)不穩(wěn)定移動網(wǎng)絡(luò)、弱網(wǎng)環(huán)境下連接可能隨時中斷需要進(jìn)度事件希望向用戶展示真實的上傳進(jìn)度條。其底層原理是 Supabase Storage 實現(xiàn)了 TUSThe Upload Server開放協(xié)議。該協(xié)議的核心價值在于上傳被打斷后可以從上次中斷的字節(jié)位置繼續(xù)而不是從頭再來??蛻舳藗?cè)既可以使用tus-js-client這樣的底層庫也可以使用像 Uppy 這類內(nèi)置 TUS 支持的上層組件庫——本示例正是官方推薦的 Uppy 路線。示例目錄結(jié)構(gòu)總覽倉庫中的 examples/storage/resumable-upload-uppy 目錄非常精簡只有以下文件examples/storage/resumable-upload-uppy/ ├── README.md # 運(yùn)行說明 ├── index.html # 純前端上傳頁面Uppy Dashboard Tus 插件 ├── supabase/ │ ├── config.toml # 本地/遠(yuǎn)端項目存儲配置 │ └── migrations/ │ └── 20241128121139_storage_rls.sql # 允許公網(wǎng)寫入的 RLS 策略 └── supabase-logo-wordmark--dark.png # 頁面 Logoindex.html是一個零構(gòu)建、單文件的瀏覽器頁面通過 CDN 引入 Uppy v3.6.1 的樣式與 ES Module無需npm install即可演示完整的 TUS 上傳閉環(huán)——這大大降低了復(fù)現(xiàn)成本。前提準(zhǔn)備創(chuàng)建存儲桶與放行策略示例假設(shè)使用 Supabase 控制臺或 SQL完成兩步前置工作創(chuàng)建存儲桶從 Supabase 控制臺的 Storage 頁面新建一個 bucket示例中默認(rèn)叫uploads。添加允許上傳的策略為storage.objects表放行公網(wǎng)INSERT官方給出 SQL 如下CREATE POLICY allow uploads ON storage.objects FOR INSERT TO public WITH CHECK (bucket_id your-bucket-name);示例倉庫中的遷移文件 examples/storage/resumable-upload-uppy/supabase/migrations/20241128121139_storage_rls.sql 就是這條策略的落地版本bucket 名為uploadsCREATE POLICY allow uploads ON storage.objects FOR INSERT TO public WITH CHECK (bucket_id uploads);配套的 supabase/config.toml 則給出了等價的項目級配置若用 CLI 管理項目可直接對照project_id resumable-upload-uppy [api] # Disable data API since we are not using the PostgREST client in this example. enabled false [storage] # The maximum file size allowed for all buckets in the project. file_size_limit 50MiB [storage.image_transformation] enabled false [storage.buckets.uploads] public true # file_size_limit 50MiB # allowed_mime_types [image/png, image/jpeg] # Uncomment to specify a local directory to upload objects to the bucket. # objects_path ./buckets/uploads其中值得注意的參數(shù)含義[api].enabled false本示例不用 PostgREST 數(shù)據(jù)客戶端因此關(guān)閉數(shù)據(jù) API[storage].file_size_limit 50MiB項目級最大上傳體積上限此處為 50MiB該上限作用于項目內(nèi)所有 bucket[storage.buckets.uploads].public true將uploads桶設(shè)為公開注釋掉的allowed_mime_types、objects_path表明你還可以按桶限定 MIME 類型或?qū)⑸蟼鲗ο舐涞奖镜啬夸浺员阏{(diào)試。注意FOR INSERT TO public意味著任何人都可向該桶寫入對象。示例僅用于演示生產(chǎn)環(huán)境請務(wù)必改用更嚴(yán)格的認(rèn)證如FOR INSERT TO authenticated WITH CHECK (bucket_id uploads AND auth.uid() owner_id)或參考本文第五節(jié)的簽名 URL 方案。配置四個核心變量打開 index.html將文件頂部的四個常量替換為你自己的值const SUPABASE_PUBLISHABLE_KEY replace-with-your-publishable-key const SUPABASE_PROJECT_ID replace-with-your-project-id const STORAGE_BUCKET replace-with-your-bucket-id const BEARER_TOKENreplace-with-your-bearer-token各變量含義如下變量含義獲取方式SUPABASE_PUBLISHABLE_KEY項目的可發(fā)布密鑰anon/publishable keySupabase 項目 Dashboard → Settings → API KeysSUPABASE_PROJECT_ID項目 refURL 中的子域項目 Settings → General形如abcdxyzSTORAGE_BUCKET存儲桶名即上文新建的 bucket 名如uploadsBEARER_TOKEN上傳鑒權(quán)令牌登錄用戶會話的access_token或服務(wù)角色密鑰演示用第 53 行據(jù)此拼接出 TUS 上傳端點(diǎn)const supabaseStorageURL https://${SUPABASE_PROJECT_ID}.supabase.co/storage/v1/upload/resumable進(jìn)階推薦使用直連 Storage 域名官方文檔特別提示上傳大文件時應(yīng)優(yōu)先使用直連存儲主機(jī)名以享受多項性能優(yōu)化。即把https://project-id.supabase.co換成https://project-id.storage.supabase.co。對應(yīng)地TUS 端點(diǎn)應(yīng)寫為const supabaseStorageURL https://${SUPABASE_PROJECT_ID}.storage.supabase.co/storage/v1/upload/resumable從源碼讀懂 Uppy 的配置整個上傳邏輯都封裝在 index.html 的一個script typemodule中。我們先實例化 Uppy 并掛載 Dashboard 組件第 55–61 行var uppy new Uppy() .use(Dashboard, { inline: true, limit: 10, target: #drag-drop-area, showProgressDetails: true, })參數(shù)作用inline: true以內(nèi)嵌方式渲染在頁面#drag-drop-area元素中而不是彈出彈窗l(fā)imit: 10同時進(jìn)行的上傳任務(wù)并發(fā)上限showProgressDetails: true在界面上展示進(jìn)度明細(xì)。接著掛載 TUS 插件第 62–74 行這是與 Supabase 對接的關(guān)鍵.use(Tus, { endpoint: supabaseStorageURL, headers: { authorization: Bearer ${BEARER_TOKEN}, apikey: SUPABASE_PUBLISHABLE_KEY, }, uploadDataDuringCreation: true, chunkSize: 6 * 1024 * 1024, allowedMetaFields: [bucketName, objectName, contentType, cacheControl], onError: function (error) { console.log(Failed because: error) }, })逐項拆解其設(shè)計意圖endpoint即上文的/storage/v1/upload/resumable地址所有 TUS 請求創(chuàng)建/上傳/續(xù)傳都發(fā)往此處headers.authorizationBearer token攜帶訪問令牌讓存儲服務(wù)端校驗身份headers.apikey攜帶項目的 publishable keyanonymity key這是所有對 Supabase 網(wǎng)關(guān)請求的標(biāo)準(zhǔn)頭uploadDataDuringCreation: true在創(chuàng)建上傳Creation請求時就攜帶首塊數(shù)據(jù)減少一次 HTTP 往返顯著加快小文件與首塊上傳chunkSize: 6 * 1024 * 1024分塊大小固定為6MB。這是當(dāng)前 TUS 客戶端與 Supabase Storage 約定必須使用的值官方在 resumable-uploads.mdx 中明確注釋“NOTE: it must be set to 6MB (for now) do not change it”allowedMetaFields聲明允許隨 TUS 上傳附帶的自定義元數(shù)據(jù)鍵服務(wù)端據(jù)此從元數(shù)據(jù)中解析對象信息onError上傳失敗時的回調(diào)便于定位問題。在 file-added 階段注入 Supabase 元數(shù)據(jù)TUS 協(xié)議的上傳創(chuàng)建請求需要把“存到哪個桶、對象叫什么、MIME 類型是什么”等信息作為元數(shù)據(jù)傳給服務(wù)端。示例在第 76–89 行用file-added事件完成注入uppy.on(file-added, (file) { const supabaseMetadata { bucketName: STORAGE_BUCKET, objectName: folder ? ${folder}/${file.name} : file.name, contentType: file.type, } file.meta { ...file.meta, ...supabaseMetadata, } console.log(file added, file) })注意第 52 行的const folder 若想在桶內(nèi)建目錄可填入子目錄前綴例如folder documents此時對象路徑變?yōu)閐ocuments/文件名。如果對照官方文檔 apps/docs/content/guides/storage/uploads/resumable-uploads.mdx 中的tus-js-client示例會發(fā)現(xiàn)還有兩個可選元數(shù)據(jù)值得了解cacheControl如3600對象緩存控制metadata可傳JSON.stringify(...)形式的自定義元數(shù)據(jù)寫入對象的user_metadata字段——注意在 Uppy 路線中需要把它加入allowedMetaFields數(shù)組才會被透傳。監(jiān)聽上傳完成事件最后監(jiān)聽complete事件在全部上傳成功后做收尾處理第 91–93 行uppy.on(complete, (result) { console.log(Upload complete! Weve uploaded these files:, result.successful) })result.successful數(shù)組中保存本次所有成功上傳的文件信息可用它刷新文件列表或跳轉(zhuǎn)詳情頁。本地啟動與驗證由于頁面完全基于瀏覽器原生 ES Module 與 CDN 依賴只需一個靜態(tài)文件服務(wù)器即可運(yùn)行。README 推薦用 Python 內(nèi)置服務(wù)器python3 -m http.server在瀏覽器打開http://localhost:8000把文件拖入 Dashboard 區(qū)域即開始上傳。頁面中還提供了一條指向官方 Resumable Uploads 文檔的鏈接第 36–38 行。與簽名 URL 變體的區(qū)別若想避免把 bucket 開放給匿名用戶可參考同目錄的姊妹示例 examples/storage/resumable-upload-signed-uppy/README.md。它的做法是每個文件在file-added時調(diào)用createSignedUploadUrl()換取一次性令牌把令牌放入x-signature請求頭完成鑒權(quán)從而實現(xiàn)無 RLS 放行策略的受限上傳。底層機(jī)制URL 時效、并發(fā)與覆蓋理解以下三條由服務(wù)端實現(xiàn)保證的語義有助于把示例改造成生產(chǎn)級代碼依據(jù)均為官方文檔對存儲服務(wù)的描述每個上傳擁有獨(dú)立的臨時 URL服務(wù)端會為每次上傳創(chuàng)建獨(dú)立的唯一 URL即使多次上傳到同一路徑也是如此所有分塊通過PATCH方法發(fā)送到該 URL。這個 URL最長有效 24 小時超時即失效、需要重新發(fā)起上傳——TUS 客戶端庫含 Uppy通常在 URL 過期后自動創(chuàng)建新 URL 繼續(xù)任務(wù)。并發(fā)沖突返回 409兩個及以上客戶端同時向同一個上傳 URL 推數(shù)據(jù)時只有一個能成功其余收到409 Conflict這避免了數(shù)據(jù)損壞兩個客戶端用不同 URL 上傳同一路徑時先完成者勝出后者同樣收到409 Conflict只有顯式設(shè)置x-upsert: true請求頭時才改為“后完成者覆蓋前者”。覆蓋寫入的默認(rèn)行為不設(shè)置x-upsert而上傳到一個已存在的路徑默認(rèn)返回400 Asset Already Exists。官方建議盡量避免覆蓋寫CDN 需要時間把變更傳播到各邊緣節(jié)點(diǎn)期間會提供過期內(nèi)容更推薦寫入新路徑。如需在 TUS 元數(shù)據(jù)或請求頭中啟用 upsert可參照官方文檔在headers中加入x-upsert: true。生產(chǎn)化要點(diǎn)小結(jié)從這一單文件示例出發(fā)落地到真實業(yè)務(wù)時建議鑒權(quán)收斂將演示用的公開寫入策略替換為authenticated限定或采用簽名 URL 方案域名直連大文件上傳使用https://project-ref.storage.supabase.co直連域名提升性能善用斷點(diǎn)續(xù)傳能力Uppy 基于file.id指紋在刷新/斷網(wǎng)后繼續(xù)未完成任務(wù)服務(wù)端保留上傳會話直至 24 小時到期控制分塊大小TUS 客戶端側(cè)chunkSize保持 6MB 約定值后續(xù)版本變化以官方文檔為準(zhǔn)。需要更系統(tǒng)的協(xié)議細(xì)節(jié)上傳 URL 語義、并發(fā)規(guī)則、x-upsert、簽名上傳可繼續(xù)閱讀倉庫內(nèi)的官方指南 apps/docs/content/guides/storage/uploads/resumable-uploads.mdx?!久赓M(fèi)下載鏈接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.項目地址: https://gitcode.com/GitHub_Trending/supa/supabase創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考