#!/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); });