I'm building a node.js+express application in which the user will input some data, the generates a PDF with pdfkit and the file is sent to the user. I'm being able to generate the file successfully, the problem is that when I download the file generated, it's empty. I can't even open the PDF, the reader (Preview, native reader in macOS) says that the file is empty. I'm using the following code:
var express = require('express');
var router = express.Router();
var guid = require('guid');
var PDFDocument = require('pdfkit');
var fs = require('fs');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/criar', function(req, res, next) {
var filename = guid.raw()+'.pdf';
var doc = new PDFDocument();
doc.pipe(fs.createWriteStream(filename));
doc.font('fonts/UbuntuMono-R.ttf')
.fontSize(25)
.text('Some text with an embedded font!', 100, 100);
doc.end();
res.download(filename, 'rifas.pdf', function(err){
if(!err){
fs.unlink(filename);
}
})
});
module.exports = router;
Do you have any idea on why my downloaded files are empty, while in the server they're being generated correctly?
Thanks!
Do you really need the physical file? If not then you can stream directly to the client:
var express = require('express');
var router = express.Router();
var PDFDocument = require('pdfkit');
var fs = require('fs');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/criar', function(req, res, next) {
var doc = new PDFDocument();
doc.pipe(res);
doc.font('fonts/UbuntuMono-R.ttf')
.fontSize(25)
.text('Some text with an embedded font!', 100, 100);
doc.end();
});
module.exports = router;
If you need both the physical file and a download response (like I do), you can wait for the close event of the stream:
let stream = fs.createWriteStream(filename);
doc.pipe(stream);
// Do whatever you need with doc
doc.end();
stream.on("close", () => {
res.download(filename, 'rifas.pdf', function(err){
if(!err){
fs.unlink(filename);
}
})
});
there are all kinds of posts about this, but I'm still not getting it.
I want to upload a *.csv and read and process its contents.
my jade file is this
//views/import.jade
extends layout
block content
h1= title
form(action="/import", method="post", enctype="multipart/form-data")
input(type="file", name="ufile")
input(type="submit", name="Upload")
--
I changed the code, but req.files is undefined
//routes/index.js
/* import page. */
router.get('/blah', function(req, res, next) {
res.render('import', { title: 'Import Data' });
});
router.post('/import', function(req, res) {
console.log(req.files);
});
module.exports = router;
Convert the uploaded file in to string, using
toString('utf8')
you can than make any operation on string like convert it to json using csvtojson package
Here is the sample code for uploading csv and than convert to json-
/* csv to json */
const express = require("express"),
app = express(),
upload = require("express-fileupload"),
csvtojson = require("csvtojson");
let csvData = "test";
app.use(upload());
app.get("/", (req, res, next) => {
res.sendFile(__dirname + "/index.html");
});
app.post("/file", (req, res) => {
/** convert req buffer into csv string ,
* "csvfile" is the name of my file given at name attribute in input tag */
csvData = req.files.csvfile.data.toString('utf8');
return csvtojson().fromString(csvData).then(json =>
{return res.status(201).json({csv:csvData, json:json})})
});
app.listen(process.env.PORT || 4000, function(){
console.log('Your node js server is running');
});
working example- csvjsonapi
Hope this solves your question, this is my method to multiple upload file:
Nodejs :
router.post('/upload', function(req , res) {
var multiparty = require('multiparty');
var form = new multiparty.Form();
var fs = require('fs');
form.parse(req, function(err, fields, files) {
var imgArray = files.imatges;
for (var i = 0; i < imgArray.length; i++) {
var newPath = './public/uploads/'+fields.imgName+'/';
var singleImg = imgArray[i];
newPath+= singleImg.originalFilename;
readAndWriteFile(singleImg, newPath);
}
res.send("File uploaded to: " + newPath);
});
function readAndWriteFile(singleImg, newPath) {
fs.readFile(singleImg.path , function(err,data) {
fs.writeFile(newPath,data, function(err) {
if (err) console.log('ERRRRRR!! :'+err);
console.log('Fitxer: '+singleImg.originalFilename +' - '+ newPath);
})
})
}
})
Make sure your form tag has enctype="multipart/form-data" attribute.
I hope this gives you a hand ;)
This question already has answers here:
File uploading with Express 4.0: req.files undefined
(13 answers)
Closed 7 years ago.
From ExpressJS 4 API, I find the req.files was invalid.
How to upload files use ExpressJS 4 now?
I just had this issue after upgrading, where req.files was undefined. I fixed it by using multer.
So,
npm install multer
and then in your app.js
var multer = require('multer');
app.use(multer({ dest: './tmp/'}));
I didn't have to change anything else after that and all my old functionality worked.
express.bodyParser is not included in express 4 by default. You must install separately. See https://github.com/expressjs/body-parser
Example :
var bodyParser = require('body-parser');
var app = connect();
app.use(bodyParser());
app.use(function (req, res, next) {
console.log(req.body) // populated!
next();
})
There is also node-formidable
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
Here is how I did it:
form = new formidable.IncomingForm();
form.uploadDir = __dirname.getParent() + "/temp/";
form.parse(req, function(err, fields, files) {
var newfile, path, uid, versionName;
uid = uuid.v4();
newfile = __dirname.getParent() + "/uploads/" + uid;
copyFile(files.file.path, newfile, function(err) {
if (err) {
console.log(err);
req.flash("error", "Oops, something went wrong! (reason: copy)");
return res.redirect(req.url);
}
fs.unlink(files.file.path, function(err) {
if (err) {
req.flash("error", "Oops, something went wrong! (reason: deletion)");
return res.redirect(req.url);
}
// done!
// ...
});
});
});
my code at Gist: https://gist.github.com/yhagio/10654836
I'm new to Express, tried from the example of the book "Node.js in Action - Chapter.9"(Uploading photo).
The author uses Express version "3.4.0" but I used "3.4.8" and I ran into this issue,
The Error message when I try to upload images:
500 TypeError: Cannot read property 'photo' of undefined
routes/photos.js
...
exports.submit = function (dir) {
return function (req, res, next) {
var img = req.files.photo.image; // ---- This 'photo' part is undefined
var name = req.body.photo.name || img.name;
var path = join(dir, img.name);
fs.rename(img.path, path, function (err) {
if (err) { return next(err); };
Photo.create({
name:name,
path:req.name
}, function (err) {
if (err) { return next(err); };
res.redirect('/');
});
});
};
};
but I found that in my app.js (bodyParser() is no longer used since 3.4.8)
app.js(In my code Express 3.4.8)
...
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json()); // Instead of bodyParser()
app.use(express.urlencoded()); // Instead of bodyParser()
...
But in author's code has bodyParser().
app.js(Author uses Express 3.4.0
...
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser()); // This is no longer used in latest version
So, I was wondering if I can fix this issue by using multer (http://expressjs-book.com/forums/topic/replacement-for-bodyparser-connect-multipart/):
app.use(express.json());
app.use(express.urlencoded());
app.use(multer({ dest: './public/photos' })); // I tried this
This didn't solve. Please help me. Thank you.
UPDATE: Solution I figured out
This code worked(routes/photos.js)
exports.submit = function (dir) {
return function(req, res, next){
var form = new multiparty.Form();
form.parse(req, function(err, fields, files){
var img = files.image[0];
var name = fields.name || img.originalFilename;
var path = join(dir, img.originalFilename);
fs.rename(img.path, path, function(err){
if(err){return next(err); };
Photo.create({
name: name,
path: img.originalFilename
}, function(err){
if(err){return next(err); };
res.redirect('/');
});
});
});
};
};
Have you given node-multiparty a try? Here's example usage from the README:
var multiparty = require('multiparty')
, http = require('http')
, util = require('util')
http.createServer(function(req, res) {
if (req.url === '/upload' && req.method === 'POST') {
// parse a file upload
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
}).listen(8080);
The author (Andrew Kelley) recommends avoiding bodyParser, so you're right to avoid it, but multiparty seems to solve a similar issue for me.
The reason it no longer works is because the node-formidable library is no longer included in Express. If you want to continue using formidable, follow these instructions.
The proper way to use body-parser with Express 4.x is:
var express = require('express'),
bodyParser = require('body-parser'),
app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
To access the files:
var formidable = require('formidable'),
form = new formidable.IncomingForm();
exports.submit = function (dir) {
return function (req, res, next) {
form.parse(req, function(err, fields, files) {
// The files object here is what you expected from req.files
});
});
});
Note: if you're trying to use multiple, set:
form.multiples = true;
Please consider newer answers that have more up-to-date information as things have changed over the years!
Since many new Node.js libraries are quickly being rendered obsolete and there are relatively few examples anyways I want to ask about uploading images using:
Node.js (v0.4.1)
Express (1.0.7)
Mongoose (1.1.0).
How have others done it?
I've found: node-formidable, but I am new to uploading images in general so I want to learn general stuff and ways of doing so using Node.js and Express.
I'll answer my own question for the first time. I found an example straight from the source. Please forgive the poor indentation. I wasn't sure how to indent properly when copying and pasting. The code comes straight from Express multipart/form-data example on GitHub.
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* Module dependencies.
*/
var express = require('../../lib/express')
, form = require('connect-form');
var app = express.createServer(
// connect-form (http://github.com/visionmedia/connect-form)
// middleware uses the formidable middleware to parse urlencoded
// and multipart form data
form({ keepExtensions: true })
);
app.get('/', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
+ '<p>Image: <input type="file" name="image" /></p>'
+ '<p><input type="submit" value="Upload" /></p>'
+ '</form>');
});
app.post('/', function(req, res, next){
// connect-form adds the req.form object
// we can (optionally) define onComplete, passing
// the exception (if any) fields parsed, and files parsed
req.form.complete(function(err, fields, files){
if (err) {
next(err);
} else {
console.log('\nuploaded %s to %s'
, files.image.filename
, files.image.path);
res.redirect('back');
}
});
// We can add listeners for several form
// events such as "progress"
req.form.on('progress', function(bytesReceived, bytesExpected){
var percent = (bytesReceived / bytesExpected * 100) | 0;
process.stdout.write('Uploading: %' + percent + '\r');
});
});
app.listen(3000);
console.log('Express app started on port 3000');
Since you're using express, just add bodyParser:
app.use(express.bodyParser());
then your route automatically has access to the uploaded file(s) in req.files:
app.post('/todo/create', function (req, res) {
// TODO: move and rename the file using req.files.path & .name)
res.send(console.dir(req.files)); // DEBUG: display available fields
});
If you name the input control "todo" like this (in Jade):
form(action="/todo/create", method="POST", enctype="multipart/form-data")
input(type='file', name='todo')
button(type='submit') New
Then the uploaded file is ready by the time you get the path and original filename in 'files.todo':
req.files.todo.path, and
req.files.todo.name
other useful req.files properties:
size (in bytes)
type (e.g., 'image/png')
lastModifiedate
_writeStream.encoding (e.g, 'binary')
You can configure the connect body parser middleware in a configuration block in your main application file:
/** Form Handling */
app.use(express.bodyParser({
uploadDir: '/tmp/uploads',
keepExtensions: true
}))
app.use(express.limit('5mb'));
See, the best thing you can do is to just upload the image to the disk and save the URL in MongoDB. Rest when you retrieve the image again. Just specify the URL, and you will get an image. The code for uploading is as follows.
app.post('/upload', function(req, res) {
// Get the temporary location of the file
var tmp_path = req.files.thumbnail.path;
// Set where the file should actually exists - in this case it is in the "images" directory.
target_path = '/tmp/' + req.files.thumbnail.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;
//
});
});
});
Now save the target path in your MongoDB database.
Again, while retrieving the image, just extract the URL from the MongoDB database, and use it on this method.
fs.readFile(target_path, "binary", function(error, file) {
if(error) {
res.writeHead(500, {"Content-Type": "text/plain"});
res.write(error + "\n");
res.end();
}
else {
res.writeHead(200, {"Content-Type": "image/png"});
res.write(file, "binary");
}
});
Try this code.It will help.
app.get('/photos/new', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
+ '<p>Data: <input type="filename" name="filename" /></p>'
+ '<p>file: <input type="file" name="file" /></p>'
+ '<p><input type="submit" value="Upload" /></p>'
+ '</form>');
});
app.post('/photos/new', function(req, res) {
req.form.complete(function(err, fields, files) {
if(err) {
next(err);
} else {
ins = fs.createReadStream(files.photo.path);
ous = fs.createWriteStream(__dirname + '/directory were u want to store image/' + files.photo.filename);
util.pump(ins, ous, function(err) {
if(err) {
next(err);
} else {
res.redirect('/photos');
}
});
//console.log('\nUploaded %s to %s', files.photo.filename, files.photo.path);
//res.send('Uploaded ' + files.photo.filename + ' to ' + files.photo.path);
}
});
});
if (!module.parent) {
app.listen(8000);
console.log("Express server listening on port %d, log on to http://127.0.0.1:8000", app.address().port);
}
You can also use the following to set a path where it saves the file.
req.form.uploadDir = "<path>";
I created an example that uses Express and Multer. It is very simple and avoids all Connect warnings
It might help somebody.
Again if you don't want to use bodyParser, the following works:
var express = require('express');
var http = require('http');
var app = express();
app.use(express.static('./public'));
app.configure(function(){
app.use(express.methodOverride());
app.use(express.multipart({
uploadDir: './uploads',
keepExtensions: true
}));
});
app.use(app.router);
app.get('/upload', function(req, res){
// Render page with upload form
res.render('upload');
});
app.post('/upload', function(req, res){
// Returns json of uploaded file
res.json(req.files);
});
http.createServer(app).listen(3000, function() {
console.log('App started');
});
For Express 3.0, if you want to use the formidable events, you must remove the multipart middleware, so you can create the new instance of it.
To do this:
app.use(express.bodyParser());
Can be written as:
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart()); // Remove this line
And now create the form object:
exports.upload = function(req, res) {
var form = new formidable.IncomingForm;
form.keepExtensions = true;
form.uploadDir = 'tmp/';
form.parse(req, function(err, fields, files){
if (err) return res.end('You found error');
// Do something with files.image etc
console.log(files.image);
});
form.on('progress', function(bytesReceived, bytesExpected) {
console.log(bytesReceived + ' ' + bytesExpected);
});
form.on('error', function(err) {
res.writeHead(400, {'content-type': 'text/plain'}); // 400: Bad Request
res.end('error:\n\n'+util.inspect(err));
});
res.end('Done');
return;
};
I have also posted this on my blog, Getting formidable form object in Express 3.0 on upload.
I know that the original question related to specific versions, but it also referred to the "latest" - #JohnAllen 's post is no longer relevant due to Expressjs bodyParser and connect-form
This demonstrates the easy to use in-built bodyParser():
/**
* Module dependencies.
*/
var express = require('express')
var app = express()
app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/home/svn/rest-api/uploaded' }))
app.get('/', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
+ '<p>Image: <input type="file" name="image" /></p>'
+ '<p><input type="submit" value="Upload" /></p>'
+ '</form>');
});
app.post('/', function(req, res, next){
res.send('Uploaded: ' + req.files.image.name)
return next()
});
app.listen(3000);
console.log('Express app started on port 3000');
There's my method to multiple upload file:
Nodejs :
router.post('/upload', function(req , res) {
var multiparty = require('multiparty');
var form = new multiparty.Form();
var fs = require('fs');
form.parse(req, function(err, fields, files) {
var imgArray = files.imatges;
for (var i = 0; i < imgArray.length; i++) {
var newPath = './public/uploads/'+fields.imgName+'/';
var singleImg = imgArray[i];
newPath+= singleImg.originalFilename;
readAndWriteFile(singleImg, newPath);
}
res.send("File uploaded to: " + newPath);
});
function readAndWriteFile(singleImg, newPath) {
fs.readFile(singleImg.path , function(err,data) {
fs.writeFile(newPath,data, function(err) {
if (err) console.log('ERRRRRR!! :'+err);
console.log('Fitxer: '+singleImg.originalFilename +' - '+ newPath);
})
})
}
})
Make sure your form has enctype="multipart/form-data"
I hope this gives you a hand ;)
Here's a way to upload your images using the formidable package, which is recommended over bodyParser in later versions of Express. This also includes the ability to resize your images on the fly:
From my website: Uploading and Resizing Images (on the fly) With Node.js and Express.
Here's the gist:
var express = require("express"),
app = express(),
formidable = require('formidable'),
util = require('util')
fs = require('fs-extra'),
qt = require('quickthumb');
// Use quickthumb
app.use(qt.static(__dirname + '/'));
app.post('/upload', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
form.on('end', function(fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Location where we want to copy the uploaded file */
var new_location = 'uploads/';
fs.copy(temp_path, new_location + file_name, function(err) {
if (err) {
console.error(err);
} else {
console.log("success!")
}
});
});
});
// Show the upload form
app.get('/', function (req, res){
res.writeHead(200, {'Content-Type': 'text/html' });
/* Display the file upload form. */
form = '<form action="/upload" enctype="multipart/form-data" method="post">'+ '<input name="title" type="text" />
'+ '<input multiple="multiple" name="upload" type="file" />
'+ '<input type="submit" value="Upload" />'+ '</form>';
res.end(form);
});
app.listen(8080);
NOTE: This requires Image Magick for the quick thumb resizing.
It will become easy to store files after converting in string you just have to convert string in image in your frontend
convert image in to base64 string using this code in your api and also don't forgot to delete file from upload folder
"img": new Buffer.from(fs.readFileSync(req.file.path)).toString("base64")
to delete the file
let resultHandler = function (err) {
if (err) {
console.log("unlink failed", err);
} else {
console.log("file deleted");
}
}
fs.unlink(req.file.path, resultHandler);
at your routes import multer
`multer const multer = require('multer');
const upload = multer({ dest: __dirname + '/uploads/images' });`
Add upload.single('img') in your request
router.post('/fellows-details', authorize([Role.ADMIN, Role.USER]),
upload.single('img'), usersController.fellowsdetails);
OR
If you want save images in localstorage and want save path in database you can try following approach
you have to install first the fs-extra which will create folder. I am creating separate folders by id's if you want to remove it you can remove it. and
to save path of image where it is uploaded add this code in your api or controller you are using to save image and and add it in database with other data
let Id = req.body.id;
let path = `tmp/daily_gasoline_report/${Id}`;
create separate folder for multer like multerHelper.js
const multer = require('multer');
let fs = require('fs-extra');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
let Id = req.body.id;
let path = `tmp/daily_gasoline_report/${Id}`;
fs.mkdirsSync(path);
cb(null, path);
},
filename: function (req, file, cb) {
// console.log(file);
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
})
let upload = multer({ storage: storage });
let createUserImage = upload.array('images', 100);
let multerHelper = {
createUserImage,
}
module.exports = multerHelper;
In your routes import multerhelper file
const multerHelper = require("../helpers/multer_helper");
router.post(multerHelper. createUserImage , function(req, res, next) {
//Here accessing the body datas.
})