Node.js上传新图前删旧图时POST路由未执行的问题排查
问题分析与解决方案
嘿,我来帮你梳理下核心问题和修复方案~
你当前代码的两个关键问题
路由注册逻辑错误
你把profilePic.post路由定义放在了uploadPic函数内部,然后用app.use('/upload', uploadPic)来挂载。但uploadPic不是标准的Express中间件,而且这个函数只会在服务器启动时执行一次——更糟的是,你并没有把profilePic这个路由对象挂载到/upload路径下,相当于你的上传路由根本没被Express识别到。异步操作顺序混乱
fs.readdir和fs.unlink都是异步操作,你当前的代码会在删除旧文件的操作还没完成时,就直接定义路由、处理上传请求,这可能导致旧文件没删干净就上传了新文件,逻辑完全不符合预期。
修复后的代码示例
var express = require('express'); var path = require('path'); var morgan = require('morgan'); var bodyParser = require('body-parser'); var app = express(); var mongoose = require('mongoose'); var port = process.env.PORT || 8000; var database = require('./config/database'); var methodOverride = require('method-override'); var cors = require('cors'); var multer = require('multer'); var fs = require('fs'); var UserProfile = require('./app/models/UserProfile.js'); // 数据库连接配置 mongoose.connect(database.remoteUrl) mongoose.Promise = global.Promise; mongoose.connection.on('error', function(e) { console.log('数据库连接失败:', e); process.exit(); }); mongoose.connection.once('open', function() { console.log("数据库连接成功"); }) // 中间件配置 app.use(morgan('dev')); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(bodyParser.json({ type: 'application/vnd.api+json' })); app.use(methodOverride('X-HTTP-Method-Override')); app.use(cors()); app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); next(); }); app.use(express.static(path.join(__dirname))); // 上传配置 var upload = multer({ dest: 'user-img/' }); var profilePic = express.Router(); const directory = 'user-img'; // 封装删除旧图片的异步函数 async function clearOldImages() { try { const files = await fs.promises.readdir(directory); for (const file of files) { await fs.promises.unlink(path.join(directory, file)); } console.log('所有旧图片已删除'); } catch (err) { console.error('删除旧图片出错:', err); throw err; } } // 正确注册上传路由 profilePic.post('/profilepic', upload.any(), async function(req, res, next) { try { // 先确保旧图片全部删除 await clearOldImages(); if (req.files && req.files.length > 0) { const filename = `${Date.now()}-${req.files[0].originalname}.jpg`; await fs.promises.rename(req.files[0].path, `user-img/${filename}`); res.send(filename); } else { res.status(400).send('未检测到上传文件'); } } catch (err) { next(err); // 把错误交给Express的错误处理中间件 } }); // 挂载路由到指定路径 app.use('/upload', profilePic); app.listen(port, () => { console.log(`服务器运行在端口 ${port}`); });
关键修复点说明
- 路由注册逻辑修正:把
profilePic路由对象直接通过app.use('/upload', profilePic)挂载,服务器启动时就完成路由注册,确保请求能被正确匹配。 - 异步操作同步化:用
fs.promises替代回调函数,配合async/await保证旧图片删除完成后,再执行新图片的上传操作,逻辑顺序完全符合你的需求。 - 错误处理优化:增加
try/catch捕获异常,避免直接throw导致服务器崩溃,同时把错误传递给Express的错误处理机制。
内容的提问来源于stack exchange,提问作者Arun-
相关产品推荐
相关产品推荐

