Node.js全局变量赋值问题:上传文件名无法在目标函数中获取
看起来你正在用Node.js实现文件上传功能,想把上传后的文件名存在全局变量里,然后在getResponseWithPython函数中获取这个文件名对吧?我先帮你梳理下当前代码的问题,再给出更可靠的实现方式。
先看你当前的代码
HTML部分
<form id="upload" action="/upload" method="POST" enctype="multipart/form-data"> <input type="submit" /> </form>
Node.js部分
// 全局变量声明 global.uploadedFileName = ''; // 上传路由 app.post('/upload', function(req, res) { var busboy = new Busboy({ headers: req.headers }); busboy.on('file', function(fieldname, file, filename, encoding, mimetype) { console.log("Context path=" + __dirname); var saveTo = path.join(__dirname + "/uploads", filename); console.log('Uploading: ' + saveTo); file.pipe(fs.createWriteStream(saveTo)); // 尝试把文件名存到全局变量 global.uploadedFileName = filename; }); busboy.on('finish', function() { console.log('Upload complete'); res.writeHead(200, { 'Connection': 'close' }); res.end("That's all folks!"); }); return req.pipe(busboy); }); function getResponseWithPython(prevMsg, cb) { // 想在这里获取全局变量里的文件名 console.log(" global.uploadedFileName::: " + global.uploadedFileName); var pythonRes = ''; var formData = { // 这里目前用的是固定文件,你应该想换成上传的文件? input_file: fs.createReadStream(__dirname + '/GoogleHeader.csv') }; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; var req = request.post({ url: 'https://google.com:443/classification/', formData: formData }, function optionalCallback(err, httpResponse, body) { if (err) { return console.error('upload failed:', err); } console.log('Upload successful! Server responded with:', body); pythonRes = body; return cb(pythonRes); }); };
你当前写法的核心问题
用global变量存文件名是个大坑,主要有两个致命问题:
- 并发冲突:Node.js是单线程处理请求的,要是有两个用户同时上传文件,后一个用户的文件名会直接覆盖前一个的,导致
getResponseWithPython拿到错误的文件名。 - 异步时序问题:文件上传是异步操作,如果在上传还没完成时调用
getResponseWithPython,会拿到空字符串。
推荐的改进方案
方案一:直接在上传完成后传递文件名(最稳妥)
把全局变量去掉,改用请求级别的变量存储文件名,上传完成后直接调用getResponseWithPython并把文件名传进去,这样完全不会有并发问题:
// 删掉全局变量声明 app.post('/upload', function(req, res) { var busboy = new Busboy({ headers: req.headers }); let uploadedFileName = ''; // 用当前请求内的变量存文件名 busboy.on('file', function(fieldname, file, filename, encoding, mimetype) { console.log("Context path=" + __dirname); var saveTo = path.join(__dirname + "/uploads", filename); console.log('Uploading: ' + saveTo); file.pipe(fs.createWriteStream(saveTo)); uploadedFileName = filename; }); busboy.on('finish', function() { console.log('Upload complete'); // 上传完成后直接调用函数,把文件名传进去 getResponseWithPython(uploadedFileName, function(pythonRes) { console.log('Python服务返回结果:', pythonRes); res.writeHead(200, { 'Connection': 'close' }); res.end("That's all folks!"); }); }); return req.pipe(busboy); }); // 修改函数,接收文件名参数 function getResponseWithPython(fileName, cb) { console.log("上传的文件名::: " + fileName); var pythonRes = ''; // 这里换成上传的文件路径 var formData = { input_file: fs.createReadStream(path.join(__dirname + "/uploads", fileName)) }; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; var req = request.post({ url: 'https://google.com:443/classification/', formData: formData }, function optionalCallback(err, httpResponse, body) { if (err) { return console.error('upload failed:', err); } console.log('Upload successful! Server responded with:', body); pythonRes = body; return cb(pythonRes); }); };
方案二:如果需要在其他请求中获取文件名(用Session)
要是getResponseWithPython是在另一个路由里调用的,那可以用Express的Session来存储每个用户的文件名(需要先安装express-session):
// 先配置Session中间件 const session = require('express-session'); app.use(session({ secret: '你的加密密钥', resave: false, saveUninitialized: true, cookie: { secure: false } // 生产环境建议开HTTPS并设为true })); // 修改上传路由 app.post('/upload', function(req, res) { var busboy = new Busboy({ headers: req.headers }); busboy.on('file', function(fieldname, file, filename, encoding, mimetype) { console.log("Context path=" + __dirname); var saveTo = path.join(__dirname + "/uploads", filename); console.log('Uploading: ' + saveTo); file.pipe(fs.createWriteStream(saveTo)); req.session.uploadedFileName = filename; // 存在Session里 }); busboy.on('finish', function() { console.log('Upload complete'); res.writeHead(200, { 'Connection': 'close' }); res.end("That's all folks!"); }); return req.pipe(busboy); }); // 修改函数,接收req参数来获取Session function getResponseWithPython(req, prevMsg, cb) { console.log("上传的文件名::: " + req.session.uploadedFileName); var pythonRes = ''; var formData = { input_file: fs.createReadStream(path.join(__dirname + "/uploads", req.session.uploadedFileName)) }; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; var req = request.post({ url: 'https://google.com:443/classification/', formData: formData }, function optionalCallback(err, httpResponse, body) { if (err) { return console.error('upload failed:', err); } console.log('Upload successful! Server responded with:', body); pythonRes = body; return cb(pythonRes); }); };
总结
永远不要用全局变量存储请求相关的数据,这会导致各种难以调试的并发问题。优先用参数传递的方式,或者用Session/数据库来存储跨请求的数据。
内容的提问来源于stack exchange,提问作者rajasekhar pippalla
相关产品推荐
相关产品推荐

