Supabase Storage 檔案管理完整教學
Supabase Storage 檔案管理完整教學
Supabase Storage 是 Supabase 平台提供的物件儲存服務,底層基於 S3 相容的 API,讓你能輕鬆在應用程式中處理圖片、影片、文件等各種檔案。搭配 Supabase 的 Row Level Security(RLS),可以精細控制檔案的存取權限。
核心概念
- Bucket(儲存桶):類似資料夾的最頂層容器,可設定公開或私有
- Object(物件):儲存桶中的實際檔案
- Public Bucket:任何人都可以透過 URL 存取檔案
- Private Bucket:需要身份驗證或簽名 URL 才能存取
初始設定
npm install @supabase/supabase-js// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);建立 Bucket
透過 SQL(推薦用於版本控制)
-- 建立公開 bucket
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);
-- 建立私有 bucket
INSERT INTO storage.buckets (id, name, public)
VALUES ('documents', 'documents', false);上傳檔案
async function uploadFile(file: File, bucket: string, path: string) {
const { data, error } = await supabase.storage
.from(bucket)
.upload(path, file, {
cacheControl: '3600',
upsert: false,
});
if (error) throw error;
return data;
}
const file = event.target.files[0];
await uploadFile(file, 'avatars', `users/${userId}/avatar.jpg`);取得檔案 URL
// 公開 bucket 的永久 URL
const { data } = supabase.storage
.from('avatars')
.getPublicUrl('users/123/avatar.jpg');
console.log(data.publicUrl);
// 私有 bucket 的簽名 URL(1 小時有效)
const { data, error } = await supabase.storage
.from('documents')
.createSignedUrl('reports/2024-annual.pdf', 3600);列出檔案
async function listUserFiles(userId: string) {
const { data, error } = await supabase.storage
.from('documents')
.list(`users/${userId}`, {
limit: 20,
offset: 0,
sortBy: { column: 'created_at', order: 'desc' },
});
if (error) throw error;
return data;
}刪除與移動檔案
// 刪除檔案
await supabase.storage
.from('avatars')
.remove(['users/123/old-avatar.jpg']);
// 移動(重新命名)
await supabase.storage
.from('documents')
.move('drafts/report.pdf', 'published/report.pdf');
// 複製
await supabase.storage
.from('documents')
.copy('templates/base.docx', `users/${userId}/new-doc.docx`);Row Level Security(RLS)設定
-- 允許已登入的使用者上傳到自己的資料夾
CREATE POLICY "使用者可上傳自己的檔案"
ON storage.objects
FOR INSERT
TO authenticated
WITH CHECK (
bucket_id = 'avatars' AND
(storage.foldername(name))[1] = auth.uid()::text
);
-- 允許公開讀取 avatars bucket
CREATE POLICY "公開讀取頭像"
ON storage.objects
FOR SELECT
TO public
USING (bucket_id = 'avatars');
-- 使用者只能刪除自己的檔案
CREATE POLICY "使用者可刪除自己的檔案"
ON storage.objects
FOR DELETE
TO authenticated
USING (
bucket_id = 'avatars' AND
(storage.foldername(name))[1] = auth.uid()::text
);圖片轉換(Image Transformation)
const { data } = supabase.storage
.from('avatars')
.getPublicUrl('users/123/avatar.jpg', {
transform: {
width: 100,
height: 100,
resize: 'cover',
format: 'webp',
quality: 80,
},
});實用工具函數
export async function uploadAvatar(userId: string, file: File): Promise<string> {
const ext = file.name.split('.').pop();
const path = `${userId}/avatar.${ext}`;
await supabase.storage.from('avatars').remove([path]);
const { error } = await supabase.storage
.from('avatars')
.upload(path, file, { upsert: true });
if (error) throw new Error(`上傳失敗: ${error.message}`);
const { data } = supabase.storage
.from('avatars')
.getPublicUrl(path, {
transform: { width: 200, height: 200, resize: 'cover' },
});
return data.publicUrl;
}總結
Supabase Storage 提供了完整的檔案管理解決方案,從基本的上傳下載、權限控制到圖片轉換,都有簡潔的 API 支援。結合 RLS 政策,你可以用幾行 SQL 實現精細的存取控制,而不需要額外開發後端邏輯。
分享這篇文章