在 JavaScript (Node.js) 中操作 S3 和云存储
S3(Simple Storage Service)是云对象存储的事实标准。无论您使用的是 Amazon S3、Yandex Object Storage、Mail.ru Cloud Storage 还是像 MinIO 这样的本地解决方案,其 API 都是统一的。在本文中,我们将介绍如何使用官方的 AWS SDK v3 从 Node.js 连接到兼容 S3 的存储。
什么是 S3,为什么需要它?
S3 允许您在“存储桶”(buckets)中存储无限数量的文件(对象)。每个对象都有一个唯一的键(路径)和元数据。主要使用场景包括:
- 存储用户文件(头像、文档)
- 数据库和日志的备份
- Web 应用的静态文件(图片、CSS、JS)
- 存储媒体文件(视频、音频)
安装和配置 AWS SDK v3
从版本 3 开始,AWS SDK 变得模块化。要操作 S3,只需安装一个包:
npm install @aws-sdk/client-s3您还需要包含访问密钥的环境变量。最好将它们存储在 .env 文件中:
AWS_ACCESS_KEY_ID=your_access_keyAWS_SECRET_ACCESS_KEY=your_secret_keyAWS_REGION=ru-central1S3_ENDPOINT=https://storage.yandexcloud.netS3_BUCKET=my-bucket连接到兼容 S3 的存储
创建一个带有自定义 endpoint(用于 Yandex Object Storage、MinIO 等)的 S3 客户端:
const { S3Client } = require('@aws-sdk/client-s3');require('dotenv').config();
const s3Client = new S3Client({ region: process.env.AWS_REGION, endpoint: process.env.S3_ENDPOINT, credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, }, forcePathStyle: true, // 对于 MinIO 和一些兼容 S3 的存储很重要});
module.exports = s3Client;S3 的基本操作
1. 上传文件 (PutObject)
从缓冲区或流上传文件:
const { PutObjectCommand } = require('@aws-sdk/client-s3');const fs = require('fs');
async function uploadFile(filePath, key) { const fileContent = fs.readFileSync(filePath); const command = new PutObjectCommand({ Bucket: process.env.S3_BUCKET, Key: key, Body: fileContent, ContentType: 'image/png', // 指定正确的 MIME 类型 });
try { const response = await s3Client.send(command); console.log('文件已上传:', response.$metadata.httpStatusCode); return `https://storage.yandexcloud.net/${process.env.S3_BUCKET}/${key}`; } catch (err) { console.error('上传错误:', err); }}2. 下载文件 (GetObject)
获取对象并保存到本地:
const { GetObjectCommand } = require('@aws-sdk/client-s3');const fs = require('fs');const stream = require('stream');const { promisify } = require('util');const pipeline = promisify(stream.pipeline);
async function downloadFile(key, destinationPath) { const command = new GetObjectCommand({ Bucket: process.env.S3_BUCKET, Key: key, });
try { const response = await s3Client.send(command); const writeStream = fs.createWriteStream(destinationPath); await pipeline(response.Body, writeStream); console.log('文件已下载:', destinationPath); } catch (err) { console.error('下载错误:', err); }}3. 获取对象列表 (ListObjectsV2)
用于显示存储桶中的文件:
const { ListObjectsV2Command } = require('@aws-sdk/client-s3');
async function listFiles(prefix = '') { const command = new ListObjectsV2Command({ Bucket: process.env.S3_BUCKET, Prefix: prefix, MaxKeys: 100, });
try { const response = await s3