文件云存储:Vercel Blob Storage
11/25/2025, 3:24:11 PM
#Next.js#Vercel
背景
个人项目中要用到文件上传(基本每个涉及到管理系统的都有吧),但是在本地开发时,当时没考虑到这个,所以文件是直接上传到 public/uploads 目录下的。本地当然可以正常工作,但一旦部署到云端(如 Vercel)后,由于文件系统是只读或临时的,上传的文件无法持久化保存,导致文件丢失。根据项目情况,想了想尽可能用少的代码和方案来解决问题。
步骤
1. 本地开发环境
在 .env 文件中新增环境变量:
USE_CLOUD_STORAGE="false"
本地开发时会自动使用 public/uploads 目录存储文件,不占用云端资源(其实主要是贵),也不大改当前代码。如果设置为true,那就是也用云端的。
2. Vercel 生产环境配置
(1) 启用 Vercel Blob Storage
- 登录 Vercel Dashboard
- 进入要启用的项目
- 点击 Storage 标签
- 点击 Create Database
- 选择 Blob 存储
- 创建后,Vercel 会自动设置
BLOB_READ_WRITE_TOKEN环境变量
(2) 设置环境变量
在 Vercel 项目设置中添加环境变量:
- 进入项目设置 → Environment Variables
- 添加以下变量:
USE_CLOUD_STORAGE = true
注意:BLOB_READ_WRITE_TOKEN 会在启用 Blob Storage 后自动设置,无需自己手动添加,所以加这一个变量就行了。
3. 代码实现思路
文件名src/lib/storage.ts
/**
* 上传文件到云存储(生产环境 - Vercel Blob)
*/
async function uploadToCloud(file: File): Promise<UploadResult> {
const filename = generateUniqueFilename(file.name);
// 上传到 Vercel Blob
const blob = await put(filename, file, {
access: 'public',
addRandomSuffix: false,
});
return {
url: blob.url,
filename,
};
}
// 上传到本地的略过了,有一堆
提供统一的上传接口:
// 单文件上传
export async function uploadFile(file: File): Promise<UploadResult> {
const useCloudStorage = process.env.USE_CLOUD_STORAGE === 'true';
// 检查是否配置了 Vercel Blob
const hasVercelBlob = !!process.env.BLOB_READ_WRITE_TOKEN;
if (useCloudStorage && hasVercelBlob) {
return uploadToCloud(file);
} else {
return uploadToLocal(file);
}
}
// 批量上传
export async function uploadFiles(files: File[]): Promise<UploadResult[]> {
const uploadPromises = files.map((file) => uploadFile(file));
return Promise.all(uploadPromises);
}
根据环境变量自动选择存储方式:有 BLOB_READ_WRITE_TOKEN 且 USE_CLOUD_STORAGE=true,使用云存储,否则使用本地存储。
然后api/upload就使用这个统一的方法:
// 使用统一的存储适配器上传文件
const results = await uploadFiles(files);
const uploadedUrls = results.map((result: UploadResult) => result.url);
前端用到这个上传业务的地方直接调用API。
4. 迁移现有的文件
如果 public/uploads 中已有文件需要迁移到云存储,那就下面操作:
- 手动上传现有文件到 Vercel Blob
- 更新数据库中的图片 URL
这个累死人,应该可以利用脚本来干,考虑到我的图片并没多少,懒癌犯了,后面再说......
关于云存储的选择
(1)Vercel Blob
免费额度有:
- 存储空间:1 GB
- 带宽:100 GB/月
- API 请求:100,000 次/月
项目用这个是考虑到是Next.js项目且部署在Vercel上面,超出免费额度后按使用量计费,具体看:Vercel Blob Pricing
(2)AWS S3
- 安装 AWS SDK:
npm install @aws-sdk/client-s3
- 修改
src/lib/storage.ts中的uploadToCloud函数使用 S3 API
(3)Cloudinary
- 安装 Cloudinary SDK:
npm install cloudinary
- 修改
src/lib/storage.ts使用 Cloudinary API