v0.app 的 Supabase、Blob 迁移到阿里云教程

v0.app 的 Supabase、Blob 迁移到阿里云教程

用 v0.app 做了一个音乐播放器,v0 采用 Next.js + Supabase + Blob 来进行开发的,做好后,要把该项目部署到自己的服务器,因为部署到 v0 自己的服务器的话,国内访问不了。。。


简单介绍下:

  • Next.js:v0 采用的前后端框架,属于 React
  • Supabase:v0 采用的 supabase.com 的云数据库(包含用户验证等服务),免费的
  • Blob:v0 采用的存储音乐等文件的云存储,收费的

部署项目

直接下载代码,部署到自己的服务器后,运行也很简单:

bash 复制代码
npm install
npm run dev

然后公网访问就可以。但是有几个问题:

  1. Supabase.com 的云数据库是国外的,直接运行的话,国内也是访问不了网站的数据。。
  2. Blob 也是国外的云存储,国内访问很慢。。。

解决方案

首先,阿里云有提供免费的 Supabase(1 核 2G 的)。其次,阿里云也有提供云存储 OSS

所以,这两个迁移到阿里云就能保证国内访问速度了。


分别如何迁移

Blob 迁移

这个不用自己去修改代码,让v0自己改。下面内容发给v0即可:

请参考下面代码,把项目里面所有上传音乐等文件的,改为在前端直接上传到阿里云 OSS:

ts 复制代码
import OSS from "ali-oss"

// STS 凭证缓存
let stsCache: {
  credentials: any
  expiration: number
} | null = null

// OSS 客户端缓存
let ossClientCache: OSS | null = null

/**
 * 获取 STS 临时凭证
 */
async function fetchSTSCredentials() {
  console.log("[v0] OSS: Fetching STS credentials...")

  // 检查缓存是否有效(提前5分钟刷新)
  if (stsCache && Date.now() < stsCache.expiration - 5 * 60 * 1000) {
    console.log("[v0] OSS: Using cached STS credentials")
    return stsCache.credentials
  }

  try {
    // https://test.com/index/web_music_player/get_oss_sts改为自己服务器的阿里云oss临时授权接口,请查看阿里云oss文档进行设置
    const response = await fetch("https://test.com/index/web_music_player/get_oss_sts", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
    })

    if (!response.ok) {
      throw new Error(`Failed to fetch STS credentials: ${response.status}`)
    }

    const data = await response.json()
    console.log("[v0] OSS: STS credentials fetched successfully")

    // 缓存凭证
    stsCache = {
      credentials: data.config,
      expiration: new Date(data.config.Expiration).getTime(),
    }

    return data.config
  } catch (error) {
    console.error("[v0] OSS: Failed to fetch STS credentials:", error)
    throw error
  }
}

/**
 * 创建 OSS 客户端(带缓存和自动刷新)
 */
async function createOSSClient(): Promise<OSS> {
  console.log("[v0] OSS: Creating OSS client...")

  // 如果客户端存在且凭证未过期,直接返回
  if (ossClientCache && stsCache && Date.now() < stsCache.expiration - 5 * 60 * 1000) {
    console.log("[v0] OSS: Using cached OSS client")
    return ossClientCache
  }

  const credentials = await fetchSTSCredentials()

  

  ossClientCache = new OSS({
    region: 'oss-cn-hangzhou',
    accessKeyId: credentials.AccessKeyId,
    accessKeySecret: credentials.AccessKeySecret,
    stsToken: credentials.SecurityToken,
    authorizationV4: true,
    endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
    bucket: credentials.BucketName,
    refreshSTSToken: async () => {
      console.log("[v0] OSS: Refreshing STS token...")
      const newCredentials = await fetchSTSCredentials()
      return {
        accessKeyId: newCredentials.AccessKeyId,
        accessKeySecret: newCredentials.AccessKeySecret,
        stsToken: newCredentials.SecurityToken,
      }
    },
    refreshSTSTokenInterval: 3000000, // 50分钟刷新一次
  })

  console.log("[v0] OSS: OSS client created successfully")
  return ossClientCache
}

/**
 * 上传文件到阿里云 OSS
 * @param file 要上传的文件
 * @param folder 文件夹路径,如 'audio'、'images'、'videos'
 * @returns 上传后的文件 URL
 */
export async function uploadToOSS(file: File, folder: string): Promise<string> {
  console.log(`[v0] OSS: Starting upload for ${file.name} to folder ${folder}`)
  console.log(`[v0] OSS: File size: ${(file.size / 1024 / 1024).toFixed(2)} MB`)

  try {
    const client = await createOSSClient()

    // 生成文件名:tlbfq/folder/timestamp-filename
    const timestamp = Date.now()
    const fileName = `tlbfq/${folder}/${timestamp}-${file.name}`

    console.log(`[v0] OSS: Uploading to ${fileName}...`)

    // 上传文件
    const result = await client.put(fileName, file, {
      headers: {
        "Content-Type": file.type,
      },
    })

    console.log("[v0] OSS: Upload successful")
    console.log("[v0] OSS: File URL:", result.url)

    return result.url
  } catch (error) {
    console.error("[v0] OSS: Upload failed:", error)
    throw error
  }
}

/**
 * 删除 OSS 文件
 * @param fileUrl 文件 URL
 */
export async function deleteFromOSS(fileUrl: string): Promise<void> {
  console.log(`[v0] OSS: Deleting file: ${fileUrl}`)

  try {
    const client = await createOSSClient()

    // 从 URL 中提取文件路径
    const url = new URL(fileUrl)
    const fileName = url.pathname.substring(1) // 移除开头的 /

    console.log(`[v0] OSS: Deleting ${fileName}...`)

    await client.delete(fileName)

    console.log("[v0] OSS: File deleted successfully")
  } catch (error) {
    console.error("[v0] OSS: Delete failed:", error)
    throw error
  }
}

Supabase 迁移

这个比较复杂,因为还涉及到迁移数据。

假设自己电脑是 Mac 系统,先安装导出工具:

bash 复制代码
brew install postgresql@17
export PATH="/opt/homebrew/opt/postgresql@17/bin:$PATH"

安装完后验证:

bash 复制代码
➜  ~ pg_dump --version
pg_dump (PostgreSQL) 17.7 (Homebrew)

然后,从 v0 复制 Supabase 链接和密码,点击 v0 聊天窗口右侧的 Vars,如下图:

然后把图片中圈起来的眼睛点开来,复制 POSTGRES_URL_NON_POOLING 的值,替换到下面的导出命令中:

bash 复制代码
pg_dump \
  "POSTGRES_URL_NON_POOLING" \
  -Fc \
  --verbose \
  -f backup.dump

在 Mac 的终端运行命令后会输出如下:

复制代码
pg_dump: 最后的内置 OID 是 16383
pg_dump: 读扩展
pg_dump: 识别扩展成员
pg_dump: 读取模式
...

这样就得到了 backup.dump,可以用于导入阿里云 Supabase。

开始申请免费的阿里云 Supabase:
阿里云 Supabase 指南

然后,创建项目。在"是否放开白名单限制"那边选择"是",注意数据库密码不能有特殊字符(如@!),用大小写和数字和下划线就可以了,数据库密码要存起来,等会儿要用。

稍微等下时间,等创建好后,点击管理,输入提供的账号密码后,就进入了supabase后台管理页面。


导入数据

在supabase后台管理页面,点击 Connect 并复制 DIRECT_URL 的值,如下图:

然后生成导入命令(替换 [YOUR-PASSWORD] 为自己设置的数据库密码):

bash 复制代码
pg_restore \
  -d "postgresql://postgres:[YOUR-PASSWORD]@sbp-bmzv1wkocfbp53cd.supabase.opentrust.net:5432/postgres" \
  backup.dump

错误信息不用管,进入阿里云 Supabase 后台页面查看,已经有表格和数据了,说明顺利导入成功。


修改项目配置

在项目根目录创建 .env.local 文件,内容如下:

env 复制代码
# ============================================
# Supabase 配置(阿里云)
# ============================================

NEXT_PUBLIC_SUPABASE_URL=https://sbp-test.supabase.opentrust.net
NEXT_PUBLIC_SUPABASE_ANON_KEY=test-key
SUPABASE_SERVICE_ROLE_KEY=test-role-key

# ============================================
# 数据库配置
# ============================================
POSTGRES_URL="postgresql://postgres:passwd@sbp-test.supabase.opentrust.net:5432/postgres"
POSTGRES_URL_NON_POOLING=postgresql://postgres:passwd@sbp-test.supabase.opentrust.net:5432/postgres
POSTGRES_PRISMA_URL=postgresql://postgres:passwd@sbp-test.supabase.opentrust.net:5432/postgres?pgbouncer=true
POSTGRES_USER=postgres # 这个不用改
POSTGRES_PASSWORD=passwd # 这个改为自己的数据库密码
POSTGRES_DATABASE=postgres # 这个不用改
POSTGRES_HOST=sbp-test.supabase.opentrust.net # 这个参考POSTGRES_URL的值来改下即可

获取 NEXT_PUBLIC_SUPABASE_URLANON_KEY 的方式如下图:

获取 POSTGRES_URL 的方式如下图:

POSTGRES_URL_NON_POOLINGPOSTGRES_PRISMA_URL 参考POSTGRES_URL的值来修改即可。

SUPABASE_SERVICE_ROLE_KEY 的值参考https://www.alibabacloud.com/help/zh/analyticdb/analyticdb-for-postgresql/user-guide/supabase/"使用Supabase项目""2. 获取API Keys"部分获取


配置完成后,重新运行:

bash 复制代码
npm run dev

即可使用阿里云 Supabase。


顺便也说下,怎么在v0那边直接修改配置,让v0也连接到阿里云的supabase,修改下图的值和上面.env.local中的一样即可:

还有,如果想查看v0的项目的数据库的内容的话,可以去下面查看:


好了,以上结束。有问题欢迎讨论。

相关推荐
cos2 小时前
我的 Claude Code 使用小记 2
前端·ai编程·claude
极客密码12 小时前
给你的AI编辑器插上翅膀!接入最强上下文引擎 - ACE(Augment Context Engine)
ai编程·claude·cursor
泯泷12 小时前
AI 界的“USB-C”协议来了:让你的 AI 拥有即插即用的“手和脚”
aigc·openai·ai编程
云计算老刘12 小时前
3.Shell 变量基础知识
chrome·正则表达式·centos·云计算
泯泷13 小时前
告别“接口地狱”,MCP 协议如何让 AI Agent 像乐高一样即插即用?
人工智能·openai·ai编程
胡玉洋13 小时前
跨时空便民服务站
ai·ai作画·llm·aigc·ai编程·ai写作
代码输入中...13 小时前
大模型项目实战:多领域智能应用开发
人工智能·机器学习·ai编程
oden14 小时前
拒绝一眼假!高效洗掉AI文章的“机器味”(附去机器化实战指南)
aigc·ai编程
珑墨19 小时前
【AI产品】当下AI产品的变现模式深度分析
人工智能·ai·数据分析·产品运营·aigc·ai编程·ai写作