我已经对这个bug进行了两周以上的故障排除,并且无法找到出错的地方。我使用FineUploader上传一个页面来上传多个文件。我有一个项目集合,每个都需要获得它自己的图像。所以我在请求参数,以确定图像对应的项目。我还有一个图片库和徽标的上传器。
我手动触发上传并在服务器上获取请求,然后设置req.on(data,function(){...})以上传文件。这永远不会被触发。
这是我的代码:
$(document).ready(function () {
window.onSubmit = function (uploaderName) {
return function (id, fileName) {
console.log("Setting parameters...")
window[uploaderName].setParams({
farm: $('input[name=farm-name]').val()
});
}
};
window.logoUploader = new qq.FineUploader({
element: $('#logo')[0],
request: {
endpoint: '/upload/farm/logo'
},
autoUpload: false,
debug: true,
validation: {
allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
sizeLimit: 1024000 // 50 kB = 50 * 1024 bytes
},
text: {
uploadButton: '<i class="icon-plus icon-white"></i> Select Logo'
},
callbacks: {
onSubmit: onSubmit("logoUploader")
}
});
window.shareLogoUploader = [];
window.shareLogoUploader[0] = new qq.FineUploader({
element: $('#share-logo-0')[0],
request: {
endpoint: '/upload/farm/share/gallery'
},
autoUpload: false,
debug: true,
validation: {
allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
sizeLimit: 1024000 // 50 kB = 50 * 1024 bytes
},
text: {
uploadButton: '<i class="icon-plus icon-white"></i> Select Logo'
}
});
window.galleryUploader = new qq.FineUploader({
element: $('#gallery')[0],
request: {
endpoint: '/upload/farm/gallery/photo'
},
autoUpload: false,
debug: true,
validation: {
allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
sizeLimit: 2024000 // around 2mbs
},
text: {
uploadButton: '<i class="icon-plus icon-white"></i> Pics'
},
callbacks: {
onComplete: function (event, id, fileName, responseJSON) {
if (responseJSON.success) {
console.log(responseJSON, fileName);
$('#thumbnails').append('<img src="/uploads/' + fileName + '" width="256px"><input type="hidden" name="photos[]" value="' + fileName + '">');
}
},
onSubmit: onSubmit("galleryUploader")
}
});
});
// Shares
var shares = [];
var sharesGallery = [];
$(function () {
$('section#shares button#add-share').click(function (e) {
e.preventDefault();
var title = $('section#shares .control-group input[name=title]');
var size = $('section#shares .control-group select[name=size]');
var type = $('section#shares .control-group select[name=type]');
var price = $('section#shares .control-group input[name=price]');
var amount = $('section#shares .control-group input[name=amount]');
var unit = $('section#shares .control-group select[name=unit]');
var discount_3 = $('input[name=discount-3]').val();
var discount_6 = $('input[name=discount-6]').val();
var discount_12 = $('input[name=discount-12]').val();
var errors = $('section#shares .control-group#errors');
var delivery_period = $('section#shares .control-group input[name=delivery_period]');
var delivery_period_es = $('section#shares .control-group input[name=delivery_period_es]');
var billing_period = $('section#shares .control-group input[name=billing_period]');
var billing_period_es = $('section#shares .control-group input[name=billing_period_es]');
var logoUploader = window.shareLogoUploader[shares.length];
var logoButtonId = "share-logo-" + shares.length;
shares.push({
title: title.val(),
currency: $('select[name=currency]').children(':selected').val(),
size: size.children(':selected').val(),
type: type.children(':selected').val(),
price: price.val() * 100.0,
unit: unit.children(':selected').val(),
amount: amount.val(),
discounts: {
'3': [discount_3, price.val() * discount_3 / 100.0],
'6': [discount_6, price.val() * discount_6 / 100.0],
'12': [discount_12, price.val() * discount_12 / 100.0]
},
delivery_period: delivery_period.val(),
delivery_period_es: delivery_period_es.val(),
billing_period: billing_period.val(),
billing_period_es: billing_period_es.val()
});
var newLogoButtonId = "share-logo-" + shares.length;
sharesGallery.push({
name: type.children(':selected').val() + "-" + size.children(':selected').val(),
logoUploader: logoUploader
})
$("#" + logoButtonId).css('display', 'none');
$("#" + logoButtonId).parent().append('<div id="' + newLogoButtonId + '"></div>');
window.shareLogoUploader[shares.length] = new qq.FineUploader({
element: $("#" + newLogoButtonId)[0],
request: {
endpoint: '/upload/farm/share/gallery'
},
autoUpload: false,
debug: true,
validation: {
allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
sizeLimit: 1024000 // 50 kB = 50 * 1024 bytes
},
text: {
uploadButton: '<i class="icon-plus icon-white"></i> Select Logo'
}
});
console.log(shares);
return;
}
});
这会正确触发上传,我在服务器上获取请求并以这种方式处理它,然后服务器挂起等待从未到来的数据,re req.on Data naver被触发。这是服务器端代码:
var fs = require('fs'), util = require('util'), uuid = require('node-uuid');
var uploadpath = __dirname + "/../public/uploads/";
var slugify = exports.slugify = function(value) {
return value.toLowerCase().replace(/-+/g, '').replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
};
// Route that takes the post upload request and sends the server response
exports.upload = function(req, res) {
winston.info("Upload parameters", [req.route.params[0], req.query.farm]);
uploadpath = __dirname + "/../public/uploads/";
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
switch(req.route.params[0]) {
case 'farm/logo':
uploadpath += "../farms/" + slugify(req.query.farm);
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
uploadpath += "/" + "logo." + req.header('x-file-name').split(".").pop();
break;
case 'farm/gallery/photo':
uploadpath += "../farms/" + slugify(req.query.farm);
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
uploadpath += "/gallery";
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
var fname = req.header('x-file-name');
uploadpath += "/" + fname;
break;
case 'farm/share/gallery':
uploadpath += "../farms/" + slugify(req.query.farm);
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
uploadpath += "/shares";
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
uploadpath += "/" + slugify(req.query.share);
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
uploadpath += "/gallery";
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
var fname = req.header('x-file-name');
uploadpath += "/" + fname;
break;
case 'courier/license':
case 'courier/registration':
uploadpath += "../couriers/" + slugify(req.query.courier);
if(!fs.existsSync(uploadpath)) {
fs.mkdirSync(uploadpath);
}
var fname = req.header('x-file-name');
uploadpath += "/" + fname;
break;
default:
var fname = req.header('x-file-name');
uploadpath += fname;
break;
}
winston.info("Uploading to ", uploadpath);
uploadFile(req, uploadpath, function(data) {
if(data.success)
res.send(JSON.stringify(data), {
'Content-Type' : 'text/plain'
}, 200);
else
res.send(JSON.stringify(data), {
'Content-Type' : 'text/plain'
}, 404);
});
}
// Mainfunction to recieve and process the file upload data asynchronously
var uploadFile = function(req, targetfile, callback) {
// Moves the uploaded file from temp directory to it's destination
// and calls the callback with the JSON-data that could be returned.
var moveToDestination = function(sourcefile, targetfile) {
moveFile(sourcefile, targetfile, function(err) {
if(!err)
callback({
success : true
});
else
callback({
success : false,
error : err
});
});
};
// Direct async xhr stream data upload, yeah baby.
if(req.xhr) {
// Be sure you can write to '/tmp/'
var tmpfile = '/tmp/' + uuid.v1();
// Open a temporary writestream
var ws = fs.createWriteStream(tmpfile);
ws.on('error', function(err) {
console.log("uploadFile() - req.xhr - could not open writestream.");
callback({
success : false,
error : "Sorry, could not open writestream."
});
});
ws.on('close', function(err) {
moveToDestination(tmpfile, targetfile);
});
// Writing filedata into writestream
req.on('data', function(data) {
ws.write(data);
});
req.on('end', function() {
ws.end();
});
}
// Old form-based upload
else {
moveToDestination(req.files.qqfile.path, targetfile);
}
};
// Moves a file asynchronously over partition borders
var moveFile = function(source, dest, callback) {
var is = fs.createReadStream(source)
is.on('error', function(err) {
console.log('moveFile() - Could not open readstream.', err);
callback('Sorry, could not open readstream.')
});
is.on('end', function() {
fs.unlinkSync(source);
callback();
});
var os = fs.createWriteStream(dest);
os.on('error', function(err) {
console.log('moveFile() - Could not open writestream.', err);
callback('Sorry, could not open writestream.');
});
is.pipe(os);
}
有人能指出我正确的方向,为每一堆文件使用不同的参数上传文件吗?
提前谢谢。
答案 0 :(得分:3)
好吧,如果有人(像我一样)需要一个体面的简单例子来实现他们的node.js / express应用程序的Fine Uploader - 我终于能够让它运行起来。事实证明,我为自己制造的所有事情都比必要的要困难得多,而Fine Uploader服务器示例并没有说清楚现在使用较新版本的Express是多么容易(这是使用express@3.1.1)。
app.use(express.bodyParser({uploadDir: __dirname + '/uploads'}));
app.get('/upload', localQuery, function(request, response) {
//This serves up our
response.render('index');
});
app.post('/uploadhander', function (request, response, next) {
var fileName = request.files.qqfile.name
var savePath = __dirname + '/process/';
//after upload, rename the file, then respond to fineuploader to tell it of success
fs.rename(request.files.qqfile.path, savePath + fileName, function(err) {
if (err != null) {
response.send(JSON.stringify({success: false, error: err}), {'Content-Type': 'text/plain'}, 404);
} else {
response.send(JSON.stringify({success: true}), {'Content-Type': 'text/plain'}, 200);
}
});
});
以下是处理Fine Uploader选项的/ upload的jade模板(您的选项显然会有所不同):
div.span12
h4 Upload a show file
#jquery-wrapped-fine-uploader
script(type='text/javascript')
jQuery(document).ready(function() {
jQuery('#jquery-wrapped-fine-uploader').fineUploader({
debug: false,
request: {
endpoint: '/uploadhander',
params: {
hostname: "#{locals.query.hostname}",
hostport: "#{locals.query.hostport}",
bucket: "#{locals.query.bucket}",
nid: "#{locals.query.nid}",
title: "#{locals.query.title}",
},
chunking: {
enabled: true,
},
resume: {
enabled: true,
},
}
});
});
我应该指出,我还没有测试过简历功能,但我可以验证是否正在处理多个上传,代码比发布的示例少得多。希望这有助于其他人!
答案 1 :(得分:0)
看起来您正在使用Node示例,或者可能是Fine Uploader Github项目的服务器目录中的Node示例的修改版本。该示例尚未更新以处理多部分编码请求,Fine Uploader现在默认为所有浏览器发送。
我对Node没有太多经验,但如果您使用的是Express,似乎您可以/应该使用req.files
来获取与请求关联的文件。
我将在Widen/fine-uploader-server repo中打开一个案例,提醒我更新节点示例。
答案 2 :(得分:0)
将multer与express.js一起使用会更有用,更简单 我的服务器端代码看起来像这样
var multer = require('multer');
var upload = multer({
dest : path.join(__dirname , '../public/uploads/')
});
router.post('/upload', function (req, res) {
upload(req, res, function (err) {
if (err)
response.send(JSON.stringify({success: false, error: err}), {'Content-Type': 'text/plain'}, 404);
else
res.send(JSON.stringify({success: true}), {'Content-Type': 'text/plain'}, 200);
});
});
module.exports = router;