Supabase存储概述 #

一、存储服务架构 #

1.1 什么是Supabase Storage #

text
Supabase Storage
├── 对象存储服务
├── 类似AWS S3
├── 支持大文件存储
├── 内置CDN加速
├── 图片处理功能
└── 细粒度权限控制

1.2 存储架构 #

text
┌─────────────────────────────────────────────────────────────┐
│                        客户端应用                            │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Supabase Storage API                     │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐           │
│  │   Upload    │ │  Download   │ │   Delete    │           │
│  └─────────────┘ └─────────────┘ └─────────────┘           │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐           │
│  │   List      │ │   Sign URL  │ │  Transform  │           │
│  └─────────────┘ └─────────────┘ └─────────────┘           │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    存储后端                                  │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐           │
│  │  Buckets    │ │  Objects    │ │    CDN      │           │
│  └─────────────┘ └─────────────┘ └─────────────┘           │
└─────────────────────────────────────────────────────────────┘

1.3 核心概念 #

概念 说明
Bucket 存储桶,文件的容器
Object 存储对象,单个文件
Path 文件路径
Public 公开访问
Private 私有访问,需要签名URL

二、存储桶 #

2.1 存储桶类型 #

text
存储桶类型
├── Public Bucket
│   ├── 公开访问
│   ├── 无需认证
│   ├── 适合公开资源
│   └── 如: 头像、公开图片
│
└── Private Bucket
    ├── 需要认证
    ├── 使用签名URL
    ├── 适合私有文件
    └── 如: 用户文档、私密资料

2.2 创建存储桶 #

typescript
// 创建公开存储桶
const { data, error } = await supabase.storage.createBucket('avatars', {
  public: true,
  fileSizeLimit: 1024 * 1024, // 1MB
  allowedMimeTypes: ['image/png', 'image/jpeg', 'image/gif'],
})

// 创建私有存储桶
const { data, error } = await supabase.storage.createBucket('documents', {
  public: false,
  fileSizeLimit: 10 * 1024 * 1024, // 10MB
})

2.3 Dashboard创建 #

text
Dashboard > Storage

创建步骤
├── 1. 点击 "Create a new bucket"
├── 2. 输入桶名称
├── 3. 选择是否公开
├── 4. 设置文件大小限制
├── 5. 设置允许的MIME类型
└── 6. 保存

三、存储桶权限 #

3.1 RLS策略 #

sql
-- 查看存储桶表
SELECT * FROM storage.buckets;

-- 查看对象表
SELECT * FROM storage.objects;

-- 存储桶权限策略
CREATE POLICY "Public Access"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');

-- 用户只能访问自己的文件
CREATE POLICY "Users can access own files"
ON storage.objects FOR ALL
USING (
    bucket_id = 'documents' AND 
    auth.uid()::text = (storage.foldername(name))[1]
);

3.2 常用策略模板 #

sql
-- 公开读取
CREATE POLICY "Public Read Access"
ON storage.objects FOR SELECT
USING (bucket_id = 'public-bucket');

-- 认证用户上传
CREATE POLICY "Authenticated users can upload"
ON storage.objects FOR INSERT
WITH CHECK (
    bucket_id = 'user-uploads' AND 
    auth.role() = 'authenticated'
);

-- 用户只能管理自己的文件
CREATE POLICY "Users manage own files"
ON storage.objects FOR ALL
USING (
    bucket_id = 'user-files' AND 
    auth.uid()::text = (storage.foldername(name))[1]
);

四、文件路径规范 #

4.1 路径结构 #

text
文件路径结构
├── bucket_id/folder/subfolder/filename.ext
│
├── 示例:
│   ├── avatars/user-123/profile.jpg
│   ├── documents/user-456/report.pdf
│   └── images/products/product-1/main.jpg
│
└── 建议: 使用用户ID作为文件夹名

4.2 路径最佳实践 #

text
路径命名建议
├── 使用用户ID隔离文件
│   └── user-123/avatar.jpg
│
├── 使用日期组织文件
│   └── 2024/01/15/document.pdf
│
├── 使用有意义的文件夹
│   └── products/product-1/images/main.jpg
│
└── 避免特殊字符
    └── 使用字母、数字、连字符、下划线

五、存储限制 #

5.1 默认限制 #

限制 免费计划 Pro计划
存储空间 1GB 100GB
文件大小 50MB 可配置
带宽 5GB/月 250GB/月

5.2 配置限制 #

typescript
// 创建桶时设置限制
const { data, error } = await supabase.storage.createBucket('uploads', {
  public: false,
  fileSizeLimit: 5 * 1024 * 1024, // 5MB
  allowedMimeTypes: ['image/*', 'application/pdf'],
})

六、存储配额管理 #

6.1 查看使用情况 #

typescript
// 获取存储使用情况
const { data, error } = await supabase.storage.listBuckets()

// 计算总大小
let totalSize = 0
for (const bucket of data || []) {
  const { data: files } = await supabase.storage
    .from(bucket.name)
    .list()
  
  files?.forEach(file => {
    totalSize += file.metadata?.size || 0
  })
}

console.log(`Total storage used: ${totalSize / 1024 / 1024} MB`)

6.2 清理未使用文件 #

sql
-- 查找孤立文件(用户已删除)
SELECT o.name, o.bucket_id
FROM storage.objects o
LEFT JOIN auth.users u ON u.id::text = (storage.foldername(o.name))[1]
WHERE u.id IS NULL;

-- 删除孤立文件
DELETE FROM storage.objects
WHERE id IN (
    SELECT o.id
    FROM storage.objects o
    LEFT JOIN auth.users u ON u.id::text = (storage.foldername(o.name))[1]
    WHERE u.id IS NULL
);

七、CDN配置 #

7.1 CDN缓存 #

text
Supabase存储内置CDN
├── 自动全球分发
├── 边缘节点缓存
├── 减少延迟
└── 提高访问速度

7.2 缓存控制 #

typescript
// 上传时设置缓存头
const { data, error } = await supabase.storage
  .from('images')
  .upload('image.jpg', file, {
    cacheControl: '3600', // 缓存1小时
    upsert: true,
  })

八、安全最佳实践 #

8.1 文件验证 #

typescript
// 验证文件类型
function validateFileType(file: File, allowedTypes: string[]): boolean {
  return allowedTypes.some(type => {
    if (type.endsWith('/*')) {
      return file.type.startsWith(type.slice(0, -1))
    }
    return file.type === type
  })
}

// 验证文件大小
function validateFileSize(file: File, maxSize: number): boolean {
  return file.size <= maxSize
}

// 上传前验证
async function uploadFile(bucket: string, path: string, file: File) {
  if (!validateFileType(file, ['image/*', 'application/pdf'])) {
    throw new Error('Invalid file type')
  }
  
  if (!validateFileSize(file, 5 * 1024 * 1024)) {
    throw new Error('File too large')
  }
  
  return supabase.storage.from(bucket).upload(path, file)
}

8.2 路径安全 #

typescript
// 安全的文件名
function sanitizeFilename(filename: string): string {
  return filename
    .toLowerCase()
    .replace(/[^a-z0-9.-]/g, '-')
    .replace(/-+/g, '-')
}

// 安全路径
function buildSafePath(userId: string, filename: string): string {
  const safeName = sanitizeFilename(filename)
  const timestamp = Date.now()
  return `${userId}/${timestamp}-${safeName}`
}

九、监控与日志 #

9.1 存储日志 #

text
Dashboard > Logs > Storage

日志内容
├── 上传操作
├── 下载操作
├── 删除操作
├── 错误信息
└── 访问统计

9.2 使用统计 #

text
Dashboard > Reports

统计信息
├── 存储使用量
├── 带宽使用
├── 请求数量
└── 错误率

十、总结 #

存储服务要点:

概念 说明
Bucket 存储桶容器
Public 公开访问
Private 私有访问
RLS 权限控制策略
CDN 全球加速

下一步,让我们学习存储桶管理!

最后更新:2026-03-28