介绍
在后端开发中,对象存储(OSS) 是文件存储、图片 / 视频托管、静态资源分发的核心组件。市面上成熟的 OSS(阿里云 OSS、腾讯云 COS)功能强大但成本较高,小型项目、私有部署场景下,我们更需要轻量、高性能、可自主掌控的私有对象存储。
如果你想搭建一套轻量、高性能、无依赖的私有对象存储(OSS),但不想从零写 Rust 服务,那 RustFS + Node.js 就是完美组合:
- RustFS:用 Rust 实现的轻量级对象存储服务,开箱即用,性能拉满
- Node.js:快速封装 RESTful API,对接 RustFS,适配业务场景
什么是 RustFS?
RustFS 是一个用 Rust 编写的轻量级对象存储服务,兼容 S3 协议,支持:
- 高性能文件读写
- 多端口服务(默认 9000 为 API 端口,9001 为控制台 / 管理端口)
- 兼容 S3 API,可直接用 S3 SDK 对接
- 支持本地文件系统存储,无需额外数据库
整体架构设计
前端/客户端 ↓ Node.js 服务(egg) ↓ RustFS 服务(端口9000) ↓ 本地文件系统(物理存储)核心优势:
- 快速部署:RustFS 容器一键启动,无需配置
- 高性能:Rust 底层 IO,比 Node.js 原生文件操作快数倍
- 兼容 S3:可直接用 AWS SDK 或 S3 客户端对接
- 易扩展:Node.js 层可轻松封装权限控制、文件处理、元数据管理
安装RustFS容器
这里是用的宝塔面板,先安装docker 在dcoker下面安装 RustFs容器
oss对象存储面板
egg接入OSS对象存储
安装 minio
npmi miniooss配置
config.rustfs={endPoint:'', // 你的服务器IP port:9001, // S3 API 端口(必须是9001,不是控制台9000) useSSL: false, accessKey:'', secretKey:'', bucket:'', // 你的桶名 externalUrl:'http://xxx.xx.xx:9001', // 外网访问地址};上传和删除
在使用的地方就可以调用上传(uploadByStream)和删除(deleteFile)的方法
'use strict';const Service=require('egg').Service;const{v4: uuidv4}=require('uuid');const Minio=require('minio');class RustfsService extends Service{constructor(ctx){super(ctx);// 初始化客户端 const config=this.app.config.rustfs;this.minioClient=new Minio.Client({endPoint: config.endPoint, port: Number(config.port), useSSL: config.useSSL, accessKey: config.accessKey, secretKey: config.secretKey,});this.bucket=config.bucket;this.externalUrl=config.externalUrl;}/** * 流式上传 * @param{Stream}fileStream - 文件可读流 * @param{String}fileExt - 文件扩展名 * @param{String}[contentType='application/octet-stream']- 文件类型 * @return{Object}上传结果 */ async uploadByStream(fileStream, fileExt, contentType='application/octet-stream'){// 生成唯一文件 key const fileName=`${uuidv4()}${fileExt}`;const fileKey=`upload/${new Date().getFullYear()}_${new Date().getMonth()+1}_${fileName}`;try{// 流式上传 const etag=await this.minioClient.putObject(this.bucket, fileKey, fileStream,{'Content-Type':contentType,});return{success: true, key: fileKey, url:`${this.externalUrl}/${this.bucket}/${fileKey}`, hash: etag.etag, fileKey,};}catch(error){this.ctx.logger.error('RustFS 流式上传失败:', error);return{success: false, message: error.message,};}}/** * 删除文件 * @param{String}fileKey - 文件key * @return{Object}删除结果 */ async deleteFile(fileKey){console.log('fileKey', fileKey);if(!fileKey){return{success: false, message:'文件key不能为空',};}try{await this.minioClient.removeObject(this.bucket, fileKey);return{success: true, message:'文件删除成功', fileKey,};}catch(error){this.ctx.logger.error('RustFS 文件删除失败:', error);return{success: false, message:`删除失败:${error.message}`, fileKey,};}}}module.exports=RustfsService;