am using express.js and uploadify to upload large file to node server, everything works fine except when more than one user login and try to upload file at same time, well it still works but it seems that the server can only upload one file at a time, so the user have to wait until the other user finish their uploading, this is so unacceptable.
here is server side code
exports.upload = function(req, res,next){
// console.log( req.body);
// console.log(req.files);
var tmp_path = req.files.product_video.path;
var target_path = 'F:/shopping/shop/' +req.body.shop_id+'/'+ req.files.product_video.name;
fs.rename(tmp_path, target_path, function(err) {
if (err) {
console.log(err)
}
else{
fs.unlink(tmp_path, function() {
if (err){
console.log(err)
}else{
exec("C:/ffmpeg/bin/ffmpeg -i shop/"+ req.body.shop_id+ '/' + req.files.product_video.name + " -ss 00:01:00.00 -r 1 -an -vframes 1 -s 250x150 -f mjpeg shop/"+ req.body.shop_id+ '/' + req.files.product_video.name + "_thumbnail.jpg", function(err){
var data = {
'thum_src':'shop/'+ req.body.shop_id+ '/' + req.files.product_video.name + "_thumbnail.jpg",
'video_name':req.files.product_video.name,
}
res.send(data);
});
}
});
}
});
};
here is front end code
$('#input_product_video').uploadify({
'formData':{'shop_id':$('#shop_id').val()},
'buttonText' : 'add',
'fileSizeLimit' : '100MB',
'fileObjName' : 'product_video',
'uploader' : '/uploads',
'swf' :'/public/javascripts/lib/uploadify/uploadify.swf',
'onUploadSuccess':function(file,data){
console.log(file);
console.log(JSON.parse(data));
console.log(response);
}
});
You shouldn't need the fs.unlink call because fs.rename is going to move the file to the correct path, not copy it, so if fs.rename succeeds, the temporary file will already be gone. Remove the whole fs.unlink block, which doesn't check for an error anyway. Then you need to make sure in every possible path through the code, you are either calling next(err) with an error or calling res.send. It looks like there are code paths in here where you will not respond and will just let the request time out. Make those changes and see if that gets it working.
Related
I have Express API which used to upload file to the files directory. Whenever I call my API res.send redirecting to a new page. How can I perform this API with reloading my current page?
app.post('/upload', function(req, res) {
let sampleFile;
let uploadPath;
if (Object.keys(req.files).length == 0) {
res.status(400).send('No files were uploaded.');
return;
}
console.log('req.files >>>', req.files); // eslint-disable-line
sampleFile = req.files.sampleFile;
console.log('lusu', sampleFile); // eslint-disable-line
uploadPath = __dirname + '/uploads/' + sampleFile.name;
sampleFile.mv(uploadPath, function(err) {
if (err) {
return res.status(500).send(err);
}
res.send('File uploaded to ' + uploadPath);
});
});
First of all, I would like to recommend multer package for file upload in node js.
instead of res.send(), try res.status(200).json({message:"successfully uploaded"})
try debugging at front end, suppose you have a function for file upload like below,
function fileUpload(){
http.post('url',{headers:headers}).then(res){
// Try to handle the response here. Do not write anything that reloads the page.
}
}
I am trying to build a REST API using a MEAN stack and I have encountered a problem. I am saving a .txt file sent in a POST request to the server and saving it using multer in an /uploads folder. I am then saving the req.file information in a collection on mongodb (path included).
The problem that I have now is that I want to be able to handle a GET request for that specific file with the ObjectId. However I want to be able to get the file from the file path and then send it to the user making the GET request.
Right now I am only returning the information corresponding to the ObjectId passed, not the file. How can I send back the whole .txt file back to the user?
exports.findById = function(req, res) {
try
{
var id = new require('mongodb').ObjectID(req.params.id);
console.log('Retrieving log: ' + id);
db.collection('logs', function(err, collection) {
if(err)
{
console.log(err);
}
else
{
collection.findOne({'_id':id}, function(err, item) {
if (err) {
console.log('Error finding log: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + item + ' found log');
console.log(item.path);
var file = __dirname + item.path;
res.download(file);
//res.send(item);
}
});
}
});
}
catch (e)
{
console.log('Id passed not correct');
res.send({'error':'Id passed not correct'});
}
};
At the end I finally got the server to respond to the GET request.
I had to find the file path of the file that had been saved into the database.
collection.findOne({'_id':id}, function(err, item) {
if (err)
{
console.log('Error finding log: ' + err);
res.send({'error':'An error has occurred'});
}
if (item)
{
//Create the path of the file wanted
filepath = path.join(__dirname, "../uploads", path.normalize(item.filename));
//Send file with the joined file path
res.sendFile(filepath);
}
else
{
console.log("Could not find entry");
res.send({'error':'No match found'});
}
});
This enabled me to send the file back by getting the full path of the file.
How can I create a folder (if the folder does not exist yet) before the image will be uploaded? I always get error ENOENT.
When I try this code:
module.exports = function(router){
router.post('/result', directory.tmp, uploader.single, function(req,res){
//some data manipulation here
});
}
//directory.js
module.exports.tmp = function(req, res, next){
mkdirp('./tmp/' + moment().format('MM-DD-YY') + '/' + moment().format('HH'), function (err) {
if (err) console.error(err)
console.log("==================================");
console.log("tmp folder created");
console.log("==================================");
});
next();
};
Though I used directory.tmp first so it will create a folder if it is not existing, I think uploader.single is executed first that is why I got that error. After receiving the error, then that's the time my app created the folder. So in other words, the file uploaded was not saved. How to fix this so it will create the folder first, then upload the file. Btw, I am using mkdirp and multer.
I would suggest you to do the next(); inside the callback of mkdirp.
Because like you did, why it creates the folder it calls next and goes further and the folder is not yet created. This is why you should wait for folder creation first.
module.exports.tmp = function(req, res, next){
mkdirp('./tmp/' + moment().format('MM-DD-YY') + '/' + moment().format('HH'), function (err) {
if (err) console.error(err)
console.log("==================================");
console.log("tmp folder created");
console.log("==================================");
next();
});
};
I am fairly new to Node.js, and I am using Express and Busboy-Connect to create a simple file upload form, for wav files only.
Here is what I am trying to do :
- start the upload
- if the mimetype is not wav, redirect to an error page
- else : write the file on the server and redirect back.
If the mimetype is valid, everything works fine, but if it isn't I cannot redirect and the browser is just hanging and eventually times out.
My understanding of it is that the browser doesn't want to redirect because it is waiting for the upload to finish, but how can I cancel the upload then within my js code ?
I could work around the issue and write the file then delete it if it's not the right mimetype, but I think it's a bit stupid to do that, I'd rather find a way to trigger an event that will stop it and redirect immediately.
Here is (a snippet of) my app code :
app.get('/', function (req, res) {
res.render(__dirname + '/public/index.ejs', {error: 0});
});
app.get('/error', function (req, res) {
res.render(__dirname + '/public/index.ejs', {error: 1});
});
app.post('/upload', function (req, res) {
var timestamp = new Date().getTime().toString();
//console.log(timestamp);
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
if ("audio/wav" != mimetype)
{
console.log("invalid mimetype"); // that prints ok
// req.busboy.end(); // I tried that but it doesn't work
res.redirect('/error');
}
else
{
console.log("Uploading: " + mimetype);
fstream = fs.createWriteStream(__dirname + '/tmp/' + timestamp + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
});
}
});
});
Can anyone point me in the right direction?
Thank you for your help !
Alright I found it in the docs of npm, if you think anyone could be interested in finding this answer from a google search you can leave it resolved, otherwise feel free to close/remove this post.
Basically there is a function on the filestream that need to be called to unblock busboy, so all I had to do to make it work is to add
file.resume();
before redirecting to the error page.
sorry, very new to Node.js here. I am having trouble getting my head around a good strategy to upload files from an iphone client into a node.js server and storing it on the server side.
For now, I can accept a binary file on the server and save it to the filesystem with the following code:
app.post('/upload', function(req, res){
// get the temporary location of the file
var tmp_path = req.files.pic.path;
// set where the file should actually exists - in this case it is in the "images" directory
var target_path = './uploads/' + req.files.pic.name;
// move the file from the temporary location to the intended location
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.pic.size + ' bytes');
});
});
console.log(req.files.pic.name);
res.send('DONE', 200);
res.end();
});
With this code, I first accept a multipart form upload of a jpeg from the iphone into the /tmp directory, then I rename and move the file to the ./uploads directory. My problem is how to save this file into the DB.
From what I've read, I have three choices (I think!)
Save the files to some upload directory and store the local path into the mongodb for later access
Save the file itself into MongoDb with a Buffer
Use grid-fs to save the file.
I have been trying #3 using this module I found called gridfs-stream (Since I am using mongoose), but I really don't understand the source code in the package.
My question is a two-parter: Among the 3 choices above, would #3 indeed be the way to go? If so, I really need some help on understanding how to use gridfs-stream.
I know the following code is wrong, but this is my attempt thus far to see if I can slot it into my existing upload code:
app.post('/upload', function(req, res){
// get the temporary location of the file
var tmp_path = req.files.pic.path;
// set where the file should actually exists - in this case it is in the "images" directory
var target_path = './uploads/' + req.files.pic.name;
// move the file from the temporary location to the intended location
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
var conn = mongoose.createConnection('localhost', 'myahkvoicedb');
conn.once('open', function () {
var gfs = Grid(conn.db, mongoose.mongo);
// all set!
var writestream = gfs.createWriteStream('req.files.pic.name');
fs.createReadStream('./uploads/').pipe(writestream);
/* // APP CRASHES HERE WITH THE FOLLOWING:
stream.js:81
throw er; // Unhandled stream error in pipe.
^
Error: EISDIR, read
*/
})
// delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.pic.size + ' bytes');
});
});
console.log(req.files.pic.name);
res.send('DONE', 200);
res.end();
});
Any help would be appreciated. Thank you!