I'm new to Node.js. I started to learn from yesterday.
I have a form with simple file upload and submit button
JS file
var http = require('http');
var fs = require('fs');
var formidable = require('formidable');
http.createServer(function(req, res){
if (req.url == '/fileupload'){
var form = new formidable.IncomingForm();
form.parse(req, function (err, files, fields){
var oldpath = files.filetoupload.path;
console.log(oldpath);
var newpath = 'F:/' + files.filestoupload.name;
console.log('Destination set!');
fs.readFile(oldpath, function (err, data){
if (err) throw err;
console.log('File read!');
fs.writeFile(newpath, data, function(err){
if (err) throw err;
res.write('Package shipped and moved');
res.end();
console.log('Newpath is' + newpath);
});
fs.unlink(oldpath, function (err){
if (err) throw err;
console.log("Temp file deleted");
});
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post">');
res.write('<input type="file" name="filetoupload"><br><br>');
res.write('<input type="submit" name="submit" value="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080);
It somehow runs on the browser, but when I hit upload button an error pops up in the command prompt
TypeError: Cannot read property 'name' of undefined
at F:\Prince\workspace\NODE JS\formidable.js:12:48
at IncomingForm.<anonymous> (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:107:9)
at IncomingForm.emit (events.js:182:13)
at IncomingForm._maybeEnd (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:557:8)
at QuerystringParser.parser.onEnd (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:458:10)
at QuerystringParser.end (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\querystring_parser.js:25:8)
at IncomingMessage.<anonymous> (F:\Prince\workspace\NODE JS\node_modules\formidable\lib\incoming_form.js:132:30)
at IncomingMessage.emit (events.js:182:13)
at endReadableNT (_stream_readable.js:1098:12)
at process.internalTickCallback (internal/process/next_tick.js:72:19)
I'll appreciate if anyone clarifies my mistake.
Ps: read comments too.
After debugging for a while I found the issues here.
There are three mistakes here.
As #Jordan S said there is an typo in line:12
filestoupload should be filestoupload
Then Incorrect callback format in form parse in line:10
form.parse(req, function (err, files, fields) to form.parse(req, function (err, fields, files)
And the final one is in the form enctype is missing
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
adding enctype="multipart/form-data" fixed the final issue.
But I still don't know what is the point of adding enctype
Updated JS File
var http = require('http');
var fs = require('fs');
var formidable = require('formidable');
http.createServer(function(req, res){
if (req.url == '/fileupload'){
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files){
var oldpath = files.filetoupload.path;
console.log(oldpath);
var newpath = 'F:/' + files.filetoupload.name;
console.log('Destination set!');
fs.readFile(oldpath, function (err, data){
if (err) throw err;
console.log('File read!');
fs.writeFile(newpath, data, function(err){
if (err) throw err;
res.write('Package shipped and moved');
res.end();
console.log('Newpath is' + newpath);
});
fs.unlink(oldpath, function (err){
if (err) throw err;
console.log("Temp file deleted");
});
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br><br>');
res.write('<input type="submit" name="submit" value="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080);
Related
I have nodejs server:
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
console.log(req.rawHeaders)
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
if (err) throw err;
var oldpath = files.file.path
var newpath = 'C:/VSI/' + files.file.name;
fs.rename(oldpath, newpath, function (err) {
//if (err) throw err;
//res.write('File uploaded and moved!');
if (err) {
res.write(JSON.stringify({
success: false,
message: 'error happend'
})
);
res.end()
throw err;
}
res.write(JSON.stringify({
success: true,
message: 'Successfully Uploaded'
})
);
res.end();
});
});
} else {
console.log(req.rawHeaders)
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080, () => {
console.log('server running')
}).on("error", () => console.log("error happend"));
and get
if (err) throw err;
^
Error: maxFileSize exceeded, received 209715683 bytes of file data
How I can upload more 200 MB with formidable?
How properly handle exceptions and why "on error" on("error", () =>) event not work"?
I tried Multer and it doesn't have 200 MB limit and work normally.
Just read the documentation:
https://www.npmjs.com/package/formidable
Default max size is 200MB, change it with (300MB for example) :
form.maxFileSize = 300 * 1024 * 1024;
Hi Im using node and formidable to submit a file in a form, this file's URL I need to save in a global variable to later use it with WATSON IBM image recognition api.
I'm new with node so I'm stuck, the variable name is newpath, I'm able to print it after the form is submitted, but can't access the variable later.
I must be doing something wrong, I really appreciate if you can point me out my mistake.
const http = require('http');
var formidable = require('formidable');
const hostname = '127.0.0.1';
const port = 3500;
var fs = require('fs');
/// WATSON
var VisualRecognitionV3 = require('watson-developer-cloud/visual-recognition/v3');
var visualRecognition = new VisualRecognitionV3({
version: '2018-03-19',
iam_apikey: 'xxxxxxx'
});
// SERVER AND FORM
const server = http.createServer((req, res) => {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = '/users/myuser/coding/visualr/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
// this is the path, variable newpath, but can't be accessed
// outside this function, tried to make it global but didn't work either
res.write('newpath');
res.end();
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
});
var images_file = fs.createReadStream(newpath);
// I want to put the variable newpath in this function: but it doesn't work...
var params = {
images_file: images_file,
};
visualRecognition.classify(params, function(err, response) {
if (err)
console.log(err);
else
console.log(JSON.stringify(response, null, 2))
});
// ENDS
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
The variable is defined within the context of the if (req.url == '/fileupload') {...} block, so it won't be available outside of that block.
To use the variable everywhere in the code, define it outside of the createServer block:
var newpath; // this variable will have global context for this file
const server = http.createServer((req, res) => {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
// set the variable to its intended value here
newpath = '/users/myuser/coding/visualr/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.write('newpath');
res.end();
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
});
console.log(newpath); // the variable should be available here, because of its context
I'm uploading an image using multipart/form-data, i want to resize it before storing it anywhere on the disk. I'm using gm to accomplish this but was not able to do it.
<form id="uploadForm" enctype="multipart/form-data" method="post" action="/upload">
<input type="file" name="userFile" />
<input type="submit" value="Upload File" name="submit">
</form>
here is the js file, now i want to resize the image without storing it anywhere on the disk using Imagemagick(gm) module in node. I'm new to node, how can we use the part and resize the image.
var express = require('express');
var multiparty = require("multiparty");
var app = express();
const sharp = require('sharp');
const gm = require('gm').subClass({imageMagick: true});
app.get('/', function(req, res){
res.sendFile('index.html' , { root : __dirname});
});
app.post('/upload', function(req, res){
console.log("in upload")
var count = 0;
var form = new multiparty.Form();
// Errors may be emitted
// Note that if you are listening to 'part' events, the same error may be
// emitted from the `form` and the `part`.
form.on('error', function(err) {
console.log('Error parsing form: ' + err.stack);
});
// Parts are emitted when parsing the form
form.on('part', function(part) {
// You *must* act on the part by reading it
// NOTE: if you want to ignore it, just call "part.resume()"
if (!part.filename) {
// filename is not defined when this is a field and not a file
console.log('got field named dd' + part.name);
// ignore field's content
part.resume();
}
if (part.filename) {
// filename is defined when this is a file
count++;
console.log('got file named ' + part.name);
// console.log(part);
part.on('data', (chunk) => {
console.log("chunck: "+chunk);
var readStream = fs.createReadStream(chunk);
gm(readStream, part.filename)
.resize(240, 240)
.noProfile()
.write('res.png', function (err) {
console.log('Ingm');
if (!err) console.log('resize done');
else
console.log('gm error: '+err);
});
});
// ignore file's content here
part.resume();
}
part.on('error', function (err) {
// decide what to do
});
});
// Close emitted after form parsed
form.on('close', function() {
console.log('Upload completed!');
res.setHeader('text/plain');
res.end('Received ' + count + ' files');
});
// Parse req
form.parse(req);
});
provide originalPath and thumbnailPath thumbnail in this case your
resize image
function resizeImage(originalPath, thumbnailPath, callback) {
const gm = require('gm').subClass({imageMagick: true});
gm(originalPath)
.resize(WIDTH, HEIGHT, "!")
.autoOrient()
.write(thumbnailPath, (err, data) => {
callback(err)
})
}
You're trying to read the uploaded file stream instead of passing it to imageMagick. Also, you're using resume() on the received file, discarding it. Try changing this:
if (part.filename) {
// filename is defined when this is a file
count++
console.log('got file named ' + part.name)
// console.log(part);
part.on('data', (chunk) => {
console.log('chunck: ' + chunk)
var readStream = fs.createReadStream(chunk)
gm(readStream, part.filename)
.resize(240, 240)
.noProfile()
.write('res.png', function (err) {
console.log('Ingm')
if (!err) console.log('resize done')
else
console.log('gm error: ' + err)
})
})
// ignore file's content here
part.resume()
}
For this:
if (part.filename) {
// filename is defined when this is a file
count++
console.log('got file named ' + part.name)
// console.log(part);
gm(part)
.resize(240, 240)
.noProfile()
.write('res.png', function (err) {
console.log('Ingm')
if (!err) console.log('resize done')
else
console.log('gm error: ' + err)
})
// ignore file's content here; but we don't want that!
// part.resume()
}
I have problem upload file nodejs. i have read
stack1
and
stack2. but i think this different case
on terminal output like this :
> Unhandled rejection Error: EXDEV: cross-device link not permitted,
> rename '/tmp/31941-53enly.png' ->
> 'public/files/complaint/Screenshot_2016-05-01_01-16-55.png'
> at Error (native)
> at Object.fs.renameSync (fs.js:681:18)
> at null.<anonymous> (/home/faris/myprojects/orchestrale-server/routes/complaintimage.js:163:20)
> at tryCatcher (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/util.js:16:23)
> at Promise._settlePromiseFromHandler (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:502:31)
> at Promise._settlePromise (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:559:18)
> at Promise._settlePromise0 (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:604:10)
> at Promise._settlePromises (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:683:18)
> at Async._drainQueue (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/async.js:138:16)
> at Async._drainQueues (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/async.js:148:10)
> at Immediate.Async.drainQueues [as _onImmediate] (/home/faris/myprojects/orchestrale-server/node_modules/sequelize/node_modules/bluebird/js/release/async.js:17:14)
> at processImmediate [as _immediateCallback] (timers.js:383:17)
my code :
if (_.isEmpty(req.files) == false) {
var tp = avatar_folder+req.files.file.name;
fs.renameSync(req.files.file.path, tp, function(err){});
var avatar = req.files.file.name;
}
code work on another distro like elementary os, but when i run project on debian jessie or ubuntu 16 LTS that error result on terminal.
any body can't help ? that code just run perfectly on elementary os and arch.
Same problem. Workaround: Read the temp file, write the file in new location and remove the temp file:
// Read the file
fs.readFile(oldpath, function (err, data) {
if (err) throw err;
console.log('File read!');
// Write the file
fs.writeFile(newpath, data, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
console.log('File written!');
});
// Delete the file
fs.unlink(oldpath, function (err) {
if (err) throw err;
console.log('File deleted!');
});
});
You can use 'mv' packgage to resolve this issue
Link NPM: https://www.npmjs.com/package/mv
How to use:
Replace some old code with fs.rename:
fs.rename(temp_path, target_path, (err) => {
if (err) {
console.log('> FileServer.jsx | route: "/files/upload" | err:', err);
throw err;
}
});
With:
const mv = require('mv');
mv(temp_path, target_path, function (err) {
if (err) {
console.log('> FileServer.jsx | route: "/files/upload" | err:', err);
throw err;
}
});
it assisted me when working with nodejs , the concept should be the same https://stackoverflow.com/a/43206506/7878987
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
var mv = require('mv');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
console.log(oldpath);
var newpath = 'F:/change path to your project dir/' + files.filetoupload.name;
mv(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}enter code here
}).listen(8080);
In order to resolve this problem, you can rewrite as:
fs.writeFile(path_where_to_write, file, function(err) {
if (err) throw err; /*do something else.*/
});
/*and then Remove the file from tmp location*/
fs.unlink(tempPath);
and for multiple files, you could iterate this block based on length of files.
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
console.log(oldpath);
var newpath = 'F:/your folder name/' + files.filetoupload.name;
fs.readFile(oldpath, function (err, data) {
if (err) throw err;
console.log('File read!');
// Write the file
fs.writeFile(newpath, data, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
console.log('File written!');
});
// Delete the file
fs.unlink(oldpath, function (err) {
if (err) throw err;
console.log('File deleted!');
});
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-
data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(8080);
You have to use fs.writeFileSync
otherwise oldfile can be deleted before copied
fs.writeFileSync(newpath, data, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
console.log('File written!');
});
// Delete the file
fs.unlink(oldpath, function (err) {
if (err) throw err;
console.log('File deleted!');
});
This issue occurs when your temp folder is in a different drive and Node code is in a different drive.
It will throw this error.
Solution is in another StackOverflow question .
What does the "EXDEV: cross-device link not permitted" error mean?
solution from this post :
As per the new NodeJS, the solution is don`t move, copy it
fs.copyFileSync(oldpath, newpath);
fs.unlink(oldpath,()=>{});
My windows 11 is in SSD and my Codes are in HDD. The uploaded image will be downloaded in windows drive and I am trying to move it to HDD.
In my case, Its working within same disc(drive) path means within c:/ , Error occurred if new path disk drive is different from temp path disk drive.
yes, you can resole this problem as.
install mv by command
npm install mv --save
add mv in your nodejs file
var mv = require('mv');
move file as:
mv('source_file', 'destination_file,' function(err) {
if (err) { throw err; }
console.log('file moved successfully');
};
I´m using formidable to handle my file uploads in NodeJs. I´m a little stuck at parsing field values.
How do I get the value of project_id to the form handler, so I can write the parameter in my filename?
<input type="text" id="project_id" value="{{projects._id}}" readonly>
EDIT
To be more specific, here´s a detailed view of my form-upload handling:
app.post('/uploads/', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
res.writeHead(200, {'content-type': 'image/jpeg'});
res.write('received upload: \n\n');
var project = fields.project_id;
res.end(util.inspect(project, {fields: fields, files: files}));
});
form.on('end', function(project, fields, files){
console.log(project);
/*Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/*The file name of the uploaded file */
var file_name = project + '.' + this.openedFiles[0].name;
I can log the var project in the form.parse part. But I don´t get the variable in the form.on('end'... part.
HTML form
<form id="uploadForm"
enctype="multipart/form-data"
action="/uploads/"
method="post">
<input type="text" name="project_id" id="project_id" value="{{projects._id}}" readonly>
<input multiple="multiple" type="file" name="upload" />
<button type="submit">Upload</button>
</form>
Formidable's end callback doesn't take any parameters, but I'm not sure you even need to call it if you're using the parse callback. I think what you're looking for is something like this:
var fs = require('fs');
app.post('/uploads', function(req, res, next) {
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
if (err) next(err);
// TODO: make sure my_file and project_id exist
fs.rename(files.my_file.path, fields.project_id, function(err) {
if (err) next(err);
res.end();
});
});
});
You would need to listen for the end() event if you chose not to use the parse callback, like this:
new formidable.IncomingForm().parse(req)
.on('file', function(name, file) {
console.log('Got file:', name);
})
.on('field', function(name, field) {
console.log('Got a field:', name);
})
.on('error', function(err) {
next(err);
})
.on('end', function() {
res.end();
});
Client side script:
//Upload the file
var fd = new FormData();
//Take the first selected file
fd.append("dbDocPath", 'invoices/' + file.name);
fd.append("file", file);
$http({
method: 'POST',
url: $rootScope.apiUrl + 'uploadDocToServer',
data: fd,
headers: {
'Content-Type': undefined
},
//prevents serializing payload. don't do it.
transformRequest: angular.identity,
}).success(function (response) {
if (response.success) {
}
})
Server side script:
var fileDir = path.join(__dirname, '/../uploads');
// create an incoming form object
var form = new formidable.IncomingForm();
var dbDocPath = '';
form.parse(req)
.on('field', function (name, field) {
//console.log('Got a field:', field);
//console.log('Got a field name:', name);
dbDocPath = field;
})
.on('file', function (name, file) {
//console.log('Got file:', name);
// specify that we want to allow the user to upload multiple files in a single request
//form.multiples = true;
// store all uploads in the /uploads directory
form.uploadDir = fileDir;
fs.rename(file.path, path.join(form.uploadDir, file.name));
// every time a file has been uploaded successfully,
// rename it to it's orignal name
var bucket = new AWS.S3();
//console.log(dbDocPath);
var params = {
Bucket: DocsConfig.bucketName,
Key: dbDocPath,
Body: fs.createReadStream(path.join(form.uploadDir, file.name)),
ACL: 'public-read'
};
bucket.putObject(params, function (perr, pres) {
if (perr) {
//console.log("Error uploading data: ", perr);
} else {
fs.unlinkSync(path.join(form.uploadDir, file.name));
//console.log("Successfully uploaded data", pres);
}
});
})
.on('error', function (err) {
res.send({'success': false, error: err});
})
.on('end', function () {
res.send({'success': true});
});
// parse the incoming request containing the form data
//form.parse(req);
Just keep one thing in mind that the sequence of sending parameters to formData() should be same as mentioned in above code as file upload needs path to upload to the destiny.