262 lines
7.6 KiB
JavaScript
262 lines
7.6 KiB
JavaScript
![]() |
#!/usr/bin/env node
|
|||
|
|
|||
|
/**
|
|||
|
* MinIO配置测试脚本
|
|||
|
* 基于用户提供的具体配置进行测试
|
|||
|
*/
|
|||
|
|
|||
|
const { S3 } = require('@aws-sdk/client-s3');
|
|||
|
const fs = require('fs');
|
|||
|
const path = require('path');
|
|||
|
|
|||
|
async function testMinIOConfig() {
|
|||
|
console.log('🔍 开始测试MinIO配置...\n');
|
|||
|
|
|||
|
// 用户提供的配置
|
|||
|
const config = {
|
|||
|
endpoint: 'http://localhost:9000',
|
|||
|
region: 'us-east-1',
|
|||
|
credentials: {
|
|||
|
accessKeyId: '7Nt7OyHkwIoo3zvSKdnc',
|
|||
|
secretAccessKey: 'EZ0cyrjJAsabTLNSqWcU47LURMppBW2kka3LuXzb',
|
|||
|
},
|
|||
|
forcePathStyle: true,
|
|||
|
};
|
|||
|
|
|||
|
const bucketName = 'test123';
|
|||
|
const uploadDir = '/opt/projects/nice/uploads';
|
|||
|
|
|||
|
console.log('📋 配置信息:');
|
|||
|
console.log(` Endpoint: ${config.endpoint}`);
|
|||
|
console.log(` Region: ${config.region}`);
|
|||
|
console.log(` Bucket: ${bucketName}`);
|
|||
|
console.log(` Upload Dir: ${uploadDir}`);
|
|||
|
console.log(` Access Key: ${config.credentials.accessKeyId}`);
|
|||
|
console.log(` Force Path Style: ${config.forcePathStyle}`);
|
|||
|
console.log();
|
|||
|
|
|||
|
try {
|
|||
|
const s3Client = new S3(config);
|
|||
|
|
|||
|
// 1. 测试基本连接和认证
|
|||
|
console.log('📡 测试连接和认证...');
|
|||
|
try {
|
|||
|
const buckets = await s3Client.listBuckets();
|
|||
|
console.log('✅ 连接和认证成功!');
|
|||
|
console.log(`📂 现有存储桶: ${buckets.Buckets?.map((b) => b.Name).join(', ') || '无'}`);
|
|||
|
} catch (error) {
|
|||
|
console.log('❌ 连接失败:', error.message);
|
|||
|
if (error.message.includes('ECONNREFUSED')) {
|
|||
|
console.log('💡 提示: MinIO服务可能未运行,请检查localhost:9000是否可访问');
|
|||
|
} else if (error.message.includes('Invalid')) {
|
|||
|
console.log('💡 提示: 检查访问密钥和密钥是否正确');
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// 2. 检查目标存储桶
|
|||
|
console.log(`\n🪣 检查存储桶 "${bucketName}"...`);
|
|||
|
let bucketExists = false;
|
|||
|
try {
|
|||
|
await s3Client.headBucket({ Bucket: bucketName });
|
|||
|
console.log(`✅ 存储桶 "${bucketName}" 存在并可访问`);
|
|||
|
bucketExists = true;
|
|||
|
} catch (error) {
|
|||
|
if (error.name === 'NotFound') {
|
|||
|
console.log(`❌ 存储桶 "${bucketName}" 不存在`);
|
|||
|
console.log('🔧 尝试创建存储桶...');
|
|||
|
try {
|
|||
|
await s3Client.createBucket({ Bucket: bucketName });
|
|||
|
console.log(`✅ 存储桶 "${bucketName}" 创建成功`);
|
|||
|
bucketExists = true;
|
|||
|
} catch (createError) {
|
|||
|
console.log(`❌ 创建存储桶失败: ${createError.message}`);
|
|||
|
return false;
|
|||
|
}
|
|||
|
} else {
|
|||
|
console.log(`❌ 检查存储桶时出错: ${error.message}`);
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!bucketExists) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// 3. 检查上传目录
|
|||
|
console.log(`\n📁 检查上传目录 "${uploadDir}"...`);
|
|||
|
try {
|
|||
|
if (!fs.existsSync(uploadDir)) {
|
|||
|
console.log('📁 上传目录不存在,正在创建...');
|
|||
|
fs.mkdirSync(uploadDir, { recursive: true });
|
|||
|
console.log('✅ 上传目录创建成功');
|
|||
|
} else {
|
|||
|
console.log('✅ 上传目录存在');
|
|||
|
}
|
|||
|
} catch (error) {
|
|||
|
console.log(`❌ 检查/创建上传目录失败: ${error.message}`);
|
|||
|
}
|
|||
|
|
|||
|
// 4. 测试文件上传
|
|||
|
console.log('\n📤 测试文件上传...');
|
|||
|
const testFileName = `test-upload-${Date.now()}.txt`;
|
|||
|
const testContent = `这是一个测试文件
|
|||
|
创建时间: ${new Date().toISOString()}
|
|||
|
用户: nice1234
|
|||
|
MinIO测试成功!`;
|
|||
|
|
|||
|
try {
|
|||
|
await s3Client.putObject({
|
|||
|
Bucket: bucketName,
|
|||
|
Key: testFileName,
|
|||
|
Body: testContent,
|
|||
|
ContentType: 'text/plain',
|
|||
|
Metadata: {
|
|||
|
'test-type': 'config-validation',
|
|||
|
'created-by': 'test-script',
|
|||
|
},
|
|||
|
});
|
|||
|
console.log(`✅ 文件上传成功: ${testFileName}`);
|
|||
|
} catch (error) {
|
|||
|
console.log(`❌ 文件上传失败: ${error.message}`);
|
|||
|
console.log('错误详情:', error);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// 5. 测试文件下载验证
|
|||
|
console.log('\n📥 测试文件下载验证...');
|
|||
|
try {
|
|||
|
const result = await s3Client.getObject({
|
|||
|
Bucket: bucketName,
|
|||
|
Key: testFileName,
|
|||
|
});
|
|||
|
|
|||
|
// 读取流内容
|
|||
|
const chunks = [];
|
|||
|
for await (const chunk of result.Body) {
|
|||
|
chunks.push(chunk);
|
|||
|
}
|
|||
|
const downloadedContent = Buffer.concat(chunks).toString();
|
|||
|
|
|||
|
if (downloadedContent === testContent) {
|
|||
|
console.log('✅ 文件下载验证成功,内容一致');
|
|||
|
} else {
|
|||
|
console.log('❌ 文件内容不一致');
|
|||
|
return false;
|
|||
|
}
|
|||
|
} catch (error) {
|
|||
|
console.log(`❌ 文件下载失败: ${error.message}`);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// 6. 测试分片上传
|
|||
|
console.log('\n🔄 测试分片上传功能...');
|
|||
|
const multipartKey = `multipart-test-${Date.now()}.dat`;
|
|||
|
try {
|
|||
|
const multipartUpload = await s3Client.createMultipartUpload({
|
|||
|
Bucket: bucketName,
|
|||
|
Key: multipartKey,
|
|||
|
Metadata: {
|
|||
|
'test-type': 'multipart-upload',
|
|||
|
},
|
|||
|
});
|
|||
|
console.log(`✅ 分片上传初始化成功: ${multipartUpload.UploadId}`);
|
|||
|
|
|||
|
// 清理测试
|
|||
|
await s3Client.abortMultipartUpload({
|
|||
|
Bucket: bucketName,
|
|||
|
Key: multipartKey,
|
|||
|
UploadId: multipartUpload.UploadId,
|
|||
|
});
|
|||
|
console.log('✅ 分片上传测试完成并清理');
|
|||
|
} catch (error) {
|
|||
|
console.log(`❌ 分片上传测试失败: ${error.message}`);
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// 7. 列出存储桶中的文件
|
|||
|
console.log('\n📂 列出存储桶中的文件...');
|
|||
|
try {
|
|||
|
const listResult = await s3Client.listObjectsV2({
|
|||
|
Bucket: bucketName,
|
|||
|
MaxKeys: 10,
|
|||
|
});
|
|||
|
|
|||
|
console.log(`✅ 存储桶中共有 ${listResult.KeyCount || 0} 个文件`);
|
|||
|
if (listResult.Contents && listResult.Contents.length > 0) {
|
|||
|
console.log('最近的文件:');
|
|||
|
listResult.Contents.slice(-5).forEach((obj, index) => {
|
|||
|
const size = obj.Size < 1024 ? `${obj.Size}B` : `${Math.round(obj.Size / 1024)}KB`;
|
|||
|
console.log(` ${index + 1}. ${obj.Key} (${size})`);
|
|||
|
});
|
|||
|
}
|
|||
|
} catch (error) {
|
|||
|
console.log(`❌ 列出文件失败: ${error.message}`);
|
|||
|
}
|
|||
|
|
|||
|
// 8. 清理测试文件
|
|||
|
console.log('\n🧹 清理测试文件...');
|
|||
|
try {
|
|||
|
await s3Client.deleteObject({
|
|||
|
Bucket: bucketName,
|
|||
|
Key: testFileName,
|
|||
|
});
|
|||
|
console.log('✅ 测试文件清理完成');
|
|||
|
} catch (error) {
|
|||
|
console.log(`⚠️ 清理测试文件失败: ${error.message}`);
|
|||
|
}
|
|||
|
|
|||
|
console.log('\n🎉 所有测试通过!您的MinIO配置完全正确!');
|
|||
|
console.log('\n📝 配置摘要:');
|
|||
|
console.log('- ✅ 连接正常');
|
|||
|
console.log('- ✅ 认证有效');
|
|||
|
console.log('- ✅ 存储桶可用');
|
|||
|
console.log('- ✅ 文件上传/下载正常');
|
|||
|
console.log('- ✅ 分片上传支持');
|
|||
|
console.log('\n💡 您可以在应用中使用这些配置:');
|
|||
|
console.log('STORAGE_TYPE=s3');
|
|||
|
console.log(`UPLOAD_DIR=${uploadDir}`);
|
|||
|
console.log(`S3_ENDPOINT=${config.endpoint}`);
|
|||
|
console.log(`S3_REGION=${config.region}`);
|
|||
|
console.log(`S3_BUCKET=${bucketName}`);
|
|||
|
console.log(`S3_ACCESS_KEY_ID=${config.credentials.accessKeyId}`);
|
|||
|
console.log('S3_SECRET_ACCESS_KEY=***');
|
|||
|
console.log('S3_FORCE_PATH_STYLE=true');
|
|||
|
|
|||
|
return true;
|
|||
|
} catch (error) {
|
|||
|
console.log(`❌ 测试过程中发生未预期错误: ${error.message}`);
|
|||
|
console.log('错误堆栈:', error.stack);
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 主函数
|
|||
|
async function main() {
|
|||
|
console.log('🚀 MinIO S3存储配置测试\n');
|
|||
|
|
|||
|
// 检查依赖
|
|||
|
try {
|
|||
|
require('@aws-sdk/client-s3');
|
|||
|
} catch (error) {
|
|||
|
console.log('❌ 缺少必要依赖 @aws-sdk/client-s3');
|
|||
|
console.log('请运行: npm install @aws-sdk/client-s3');
|
|||
|
process.exit(1);
|
|||
|
}
|
|||
|
|
|||
|
const success = await testMinIOConfig();
|
|||
|
|
|||
|
if (success) {
|
|||
|
console.log('\n✅ 测试完成:MinIO配置正确,可以正常使用!');
|
|||
|
process.exit(0);
|
|||
|
} else {
|
|||
|
console.log('\n❌ 测试失败:请检查上述错误并修复配置');
|
|||
|
process.exit(1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
main().catch((error) => {
|
|||
|
console.error('❌ 脚本执行失败:', error);
|
|||
|
process.exit(1);
|
|||
|
});
|