如何使用Node.js与hapi@8.8.1上传并处理CSV文件
Alright, let's break this down step by step since you're stuck with hapi@8.8.1 and can't update any dependencies. I’ve worked with this exact Hapi version before, so here’s how to nail each of your requirements:
root/uploaded_csv) Hapi 8.x handles file uploads via route payload configuration. First, make sure your target directory exists (old Node versions might not support recursive directory creation natively, so I’ll cover both cases).
const Hapi = require('hapi'); const fs = require('fs'); const path = require('path'); const server = new Hapi.Server(); server.connection({ port: 3000 }); // Create upload directory (handle pre-v10.12.0 Node versions) const uploadDir = path.join(__dirname, 'root', 'uploaded_csv'); function createDirRecursive(dir) { if (!fs.existsSync(dir)) { createDirRecursive(path.dirname(dir)); fs.mkdirSync(dir); } } createDirRecursive(uploadDir); server.route({ method: 'POST', path: '/upload-csv', config: { payload: { output: 'file', // Save uploaded file to temp storage first parse: true, maxBytes: 5 * 1024 * 1024, // Limit to 5MB (adjust as needed) allow: 'multipart/form-data' } }, handler: function(request, reply) { const uploadedFile = request.payload.csvFile; // Match your frontend's file input name const uniqueFileName = `${Date.now()}-${uploadedFile.hapi.filename}`; const targetPath = path.join(uploadDir, uniqueFileName); // Move temp file to our target directory fs.rename(uploadedFile.path, targetPath, (err) => { if (err) return reply(err).code(500); reply({ message: 'Local upload successful', localPath: targetPath, fileName: uniqueFileName }); }); } }); server.start((err) => { if (err) throw err; console.log(`Server running at ${server.info.uri}`); });
For CSV parsing, use csv-parse@1.3.3—it’s compatible with old Node and Hapi versions. Install it first with npm install csv-parse@1.3.3.
Here’s how to integrate parsing and database querying (example uses MySQL; adjust for your DB):
const csvParse = require('csv-parse'); const mysql = require('mysql'); // Use a version compatible with your Node setup (e.g., v2.18.1) // Initialize DB connection const dbConn = mysql.createConnection({ host: 'YOUR_DB_HOST', user: 'YOUR_DB_USER', password: 'YOUR_DB_PASS', database: 'YOUR_DB_NAME' }); function processCsvAndQueryUsers(filePath) { return new Promise((resolve, reject) => { const emails = []; fs.createReadStream(filePath) .pipe(csvParse({ columns: false, skip_empty_lines: true })) .on('data', (row) => { // Grab 2nd column (index 1, since arrays are zero-indexed) if (row.length >= 2) emails.push(row[1].trim()); }) .on('end', () => { // Remove duplicate emails to avoid redundant queries const uniqueEmails = [...new Set(emails)]; if (uniqueEmails.length === 0) return resolve({ foundUsers: [] }); // Parameterized query to prevent SQL injection const query = 'SELECT * FROM users WHERE email IN (?)'; dbConn.query(query, [uniqueEmails], (err, results) => { if (err) reject(err); else resolve({ processedEmails: uniqueEmails, foundUsers: results }); }); }) .on('error', reject); }); } // Update the upload handler to include this logic handler: function(request, reply) { // ... (previous local upload code) ... fs.rename(uploadedFile.path, targetPath, (err) => { if (err) return reply(err).code(500); processCsvAndQueryUsers(targetPath) .then((dbResults) => { reply({ message: 'Local upload and user query complete', localPath: targetPath, fileName: uniqueFileName, totalEmailsProcessed: dbResults.processedEmails.length, usersFound: dbResults.foundUsers.length }); }) .catch((dbErr) => reply(dbErr).code(500)); }); }
Use AWS SDK v2.x (v3.x doesn’t support old Node versions). Install it with npm install aws-sdk@2.1300.0.
const AWS = require('aws-sdk'); // Configure S3 client const s3 = new AWS.S3({ accessKeyId: 'YOUR_AWS_ACCESS_KEY', secretAccessKey: 'YOUR_AWS_SECRET_KEY', region: 'YOUR_AWS_REGION' // e.g., 'us-east-1' }); function uploadToS3(localFilePath, fileName, bucketName) { return new Promise((resolve, reject) => { const fileStream = fs.createReadStream(localFilePath); fileStream.on('error', reject); const s3Params = { Bucket: bucketName, Key: `uploaded-csv/${fileName}`, // Path in your S3 bucket Body: fileStream, ContentType: 'text/csv' }; s3.upload(s3Params, (err, data) => { if (err) reject(err); else resolve({ s3Url: data.Location, s3Key: data.Key }); }); }); } // Update the handler to run all three tasks in sequence handler: function(request, reply) { // ... (previous local upload code) ... fs.rename(uploadedFile.path, targetPath, (err) => { if (err) return reply(err).code(500); processCsvAndQueryUsers(targetPath) .then((dbResults) => { return uploadToS3(targetPath, uniqueFileName, 'YOUR_S3_BUCKET_NAME'); }) .then((s3Results) => { // Optional: Delete local file if you don't need it anymore fs.unlink(targetPath, (unlinkErr) => { if (unlinkErr) console.warn('Failed to delete local file:', unlinkErr); reply({ message: 'All tasks completed successfully', s3Url: s3Results.s3Url, totalEmailsProcessed: dbResults.processedEmails.length, usersFound: dbResults.foundUsers.length }); }); }) .catch((taskErr) => reply(taskErr).code(500)); }); }
内容的提问来源于stack exchange,提问作者Jitendra

