LogoMkSaaS文档

存储

学习如何设置和使用云存储进行文件上传和媒体处理

MkSaaS 使用 Amazon S3 和兼容 S3 的服务(如 Cloudflare R2)进行文件存储和媒体处理,为存储图像和其他媒体文件提供可靠且可扩展的解决方案。

设置

要在 MkSaaS 中设置存储,请按照以下步骤配置必要的环境变量:

Cloudflare R2(推荐)

  1. cloudflare.com 创建 Cloudflare 账户
  2. 创建新的 R2 存储桶:
    • 选择全局唯一的存储桶名称(例如 your-project-name
    • 选择靠近目标受众的区域
    • 根据您的需要设置其他选项
  3. 允许对存储桶的公共访问:
    • Settings > Public Development URL,点击 启用
    • 将公共访问 URL 保存为 STORAGE_PUBLIC_URL
    • 为存储桶的公共访问设置自定义域名
  4. 创建新的 API 令牌:
    • R2 > API > Manage API Tokens,点击 Create User API Token
    • 将权限设置为对存储桶的 Object Read & Write
    • 创建 API 令牌,获取 Access Key IDSecret Access Key
  5. 设置以下环境变量:
.env
STORAGE_REGION=your-region-or-auto
STORAGE_BUCKET_NAME=your-bucket-name
STORAGE_ACCESS_KEY_ID=your-access-key
STORAGE_SECRET_ACCESS_KEY=your-secret-key
STORAGE_ENDPOINT=https://xxx.r2.cloudflarestorage.com
STORAGE_PUBLIC_URL=https://pub-xxx.r2.dev
  1. 更新网站配置以使用 R2 作为存储提供商:
src/config/website.tsx
export const websiteConfig = {
  // ...其他配置
  storage: {
    provider: 's3',
  },
  // ...其他配置
}

将存储提供商设置为 s3,因为 Cloudflare R2 与 Amazon S3 兼容。

Amazon S3

  1. aws.amazon.com 创建 AWS 账户

  2. 创建新的 S3 存储桶:

    • 选择全局唯一的存储桶名称(例如 your-project-name
    • 选择靠近目标受众的区域
    • 如果您希望文件可公开访问,禁用Block all public access选项
    • 根据您的需要设置其他选项
  3. 添加存储桶策略以允许公共访问,进入到Permissions选项卡并添加:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*"
    }
  ]
}
  1. 创建具有 S3 访问权限的 IAM 用户:

    • 导航到 IAM 服务
    • 创建具有 S3 权限的新策略:GetObjectPutObjectDeleteObjectListBucket
    • 创建具有Programmatic access权限的新 IAM 用户
    • 附加您创建的策略
    • 保存Access Key IDSecret Access Key
  2. 添加以下环境变量:

.env
STORAGE_REGION=your-region
STORAGE_BUCKET_NAME=your-bucket-name
STORAGE_ACCESS_KEY_ID=your-access-key
STORAGE_SECRET_ACCESS_KEY=your-secret-key
  1. 更新网站配置以使用 S3 作为存储提供商:
src/config/website.tsx
export const websiteConfig = {
  // ...其他配置
  storage: {
    provider: 's3',
  },
  // ...其他配置
}

S3 兼容的替代方案

MkSaaS 与任何 S3 兼容的存储服务兼容,包括:

使用这些替代方案时,请确保在环境变量中设置正确的端点。

如果您正在设置环境,现在可以回到环境配置文档并继续。本文档的其余部分可以稍后阅读。

环境配置

设置环境变量


存储系统架构

MkSaaS 中的存储系统设计包含以下组件:

index.ts
types.ts
client.ts
README.md

这种模块化结构使得使用新提供商和功能扩展存储系统变得容易。

核心功能

  • 服务器端的文件上传
  • 浏览器端的文件上传
  • 支持 Amazon S3 和兼容 S3 的存储服务
  • 更好的文件管理,使用文件夹组织文件
  • 自动生成路径和文件命名
  • 可配置的存储区域和存储桶设置
  • 支持公共和私有文件存储

使用方法

基本文件操作

MkSaaS 为常见文件操作提供简单的实用程序:

import { uploadFile, deleteFile } from '@/storage';

// 将文件上传到存储
const { url, key } = await uploadFile(
  fileBuffer,
  'original-filename.jpg',
  'image/jpeg',
  'uploads/images'
);

// 从存储中删除文件
await deleteFile(key);

浏览器端上传文件

要直接从浏览器上传文件,请使用 uploadFileFromBrowser 函数:

'use client';

import { uploadFileFromBrowser } from '@/storage/client';

// 在您的 React 组件中
async function handleFileUpload(event) {
  const file = event.target.files[0];

  try {
    const { url, key } = await uploadFileFromBrowser(file, 'uploads/images');
    console.log('文件已上传:', url);
  } catch (error) {
    console.error('上传失败:', error);
  }
}

与表单组件配合使用

以下是将存储模块与表单组件配合使用的示例:

ImageUploader.tsx
'use client';

import { useState } from 'react';
import { uploadFileFromBrowser } from '@/storage/client';
import { Button } from '@/components/ui/button';

export function ImageUploader() {
  const [isUploading, setIsUploading] = useState(false);
  const [imageUrl, setImageUrl] = useState<string | null>(null);

  async function handleFileChange(event: React.ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0];
    if (!file) return;

    try {
      setIsUploading(true);
      const { url } = await uploadFileFromBrowser(file, 'profile-images');
      setImageUrl(url);
    } catch (error) {
      console.error('上传失败:', error);
    } finally {
      setIsUploading(false);
    }
  }

  return (
    <div className="space-y-4">
      <div className="flex items-center gap-4">
        <Button
          variant="outline"
          onClick={() => document.getElementById('file-upload')?.click()}
          disabled={isUploading}
        >
          {isUploading ? '上传中...' : '上传图像'}
        </Button>
        <input
          id="file-upload"
          type="file"
          accept="image/*"
          className="hidden"
          onChange={handleFileChange}
        />
      </div>

      {imageUrl && (
        <div className="w-32 h-32 relative">
          <img
            src={imageUrl}
            alt="已上传的图像"
            className="object-cover w-full h-full rounded-md"
          />
        </div>
      )}
    </div>
  );
}

自定义存储提供商

创建自定义提供商

MkSaaS 使得使用新提供商扩展存储系统变得容易:

  1. src/storage/provider 目录中创建新文件

  2. 实现 StorageProvider 接口

src/storage/provider/custom-provider.ts
import {
  PresignedUploadUrlParams,
  StorageProvider,
  UploadFileParams,
  UploadFileResult
} from '@/storage/types';

export class CustomStorageProvider implements StorageProvider {
  constructor() {
    // 初始化您的提供商
  }

  public getProviderName(): string {
    return 'CustomProvider';
  }

  async uploadFile(params: UploadFileParams): Promise<UploadFileResult> {
    // 上传文件的实现
    return { url: 'https://example.com/file.jpg', key: 'file.jpg' };
  }

  async deleteFile(key: string): Promise<void> {
    // 删除文件的实现
  }
}
  1. index.ts 中更新提供商选择:
src/storage/index.ts
import { CustomStorageProvider } from './provider/custom-provider';

export const initializeStorageProvider = (): StorageProvider => {
  if (!storageProvider) {
    if (websiteConfig.storage.provider === 's3') {
      storageProvider = new S3Provider();
    } else if (websiteConfig.storage.provider === 'custom') {
      storageProvider = new CustomStorageProvider();
    } else {
      throw new Error(
        `不支持的存储提供商: ${websiteConfig.storage.provider}`
      );
    }
  }
  return storageProvider;
};

最佳实践

  1. 文件组织:使用文件夹按类型或用途组织文件(例如 uploads/imagesdocuments/contracts
  2. 文件大小限制:设置合理的文件大小限制以防止滥用
  3. 文件类型验证:在客户端和服务器端验证文件类型以确保安全

视频教程

下一步

现在您了解了如何在 MkSaaS 中使用文件存储,探索这些相关主题: