Download returning empty file - node.js

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);
}
})
});

Related

How to save POST to global variable in node

I am sending json by POST to nodejs, I declared router.post in index.js, (/routes)
How I can save it so I can actually use that later on? Keep in mind that every 60sec I am getting new data that should replace the old one.
I am listening on port 3000
var express = require('express');
var router = express.Router();
var saveme
/* GET home page. */
router.get('/index', function(req, res, next) {
res.render('index', { title: 'RLH' });
});
router.post('/index', function(req, res, next) {
data = req.body;
console.log('OK')
});
module.exports = router;
I don't know how can I save what I get trough POST, so later on I can use it on my website.
There are multiple ways to use Global variable:
Method1
Using app.locals :
declare app.locals.data = {}; in main file (ex:server.js)
var app = express();
app.locals.data = {};
app.locals available to req object as req.app.locals. When you have new data you can update it as :
req.app.locals.data = req.body;
Method2
Using global object
Assign new data as global.data = req.body
You can always access data as global.data in same or different module
Method3(Recommended)
Create file globaldata.js with below code
module.exports = {};
Import globaldata.js where you need to access or update global data as
var globaldata = require('./globaldata.js');
globaldata = req.body;
What is recommended? global method for small apps, module.exports for big apps.
You can read below ref. for more details:
https://www.hacksparrow.com/nodejs/global-variables-in-node-js.html
http://expressjs.com/en/api.html#app.locals
If by saving the data you mean storing it in a variable you can do:
var express = require('express');
var router = express.Router();
var saveme;
/* GET home page. */
router.get('/index', function(req, res, next) {
if (saveme) {
// you can use `saveme`
res.render('index' + saveme.toString(), { title: 'RLH' });
}
else {
res.render('index', { title: 'RLH' });
}
});
router.post('/index', function(req, res, next) {
data = req.body;
// set `saveme`
saveme = data;
});
module.exports = router;

Reading png image from request using body-parser and Express

I am sending the following request to my server using postman:
I try to access the image in my application using the following code:
app.js
var express = require('express');
var bodyParser = require('body-parser');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
app.use(bodyParser.raw({
type: 'image/png',
limit: '10mb'
}));
app.use('/', indexRouter);
app.use('/users', usersRouter);
module.exports = app;
index.js (router)
var express = require('express');
const router = express.Router();
var Jimp = require('jimp');
/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});
router.post('/a', function(req, res) {
var image = req.body;
try{
Jimp.read(image, (err, input) => {
if (err) throw err;
input.sepia();
input.getBuffer(Jimp.AUTO, (err, output) => {
if(err) throw err;
res.writeHead(200, {'Content-Type': 'image/png' });
return res.end(output, 'binary');
});
});
}catch (err){
return res.status(400).send(`Error: ${err.message}`).end();
}
});
module.exports = router;
I was first using a form (with the help of express-fileupload library) to send the image and this worked fine, so I know the problem has to be somewhere before the line var image = req.body.
For the Jimp functions (image processing library) to work, the image has to be a buffer representing the png image.
When running console.log(image), the console outputs {}.
Can anybody show me a way to read the png as a buffer when it is sent as a Binary file?
Nevermind, I just had to change the Content-Type header in my request to image/png -.-
can you rewrite function with lib multer?
const multer = require('multer')
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
router.post('/a', upload.single('image'), function(req, res, next) {
const image = req.file.buffer
});
or with formidable?
var formidable = require('formidable' );
router.post('/a', (req, res) => {
const form = new formidable.IncomingForm();
form.parse(req, (error, fields, files) => {
const image = files.image;
})
});

How to upload and download a file in a single service call in nodejs?

I can upload a file via postman and download a file from server in two different service .. But what i need is ..In a single call i should able to upload the file to server ,then perform some operation after performing some operation i should able to download the file automatically.
Here is my code.
My firsts service(file upload operation)
var express = require('express');
var fs = require('fs');
var formidable = require('formidable');
var router = express.Router();
/* GET home page. */
router.post('/', function(req, res, next) {
var form = new formidable.IncomingForm();
form.uploadDir="./file"
form.keepExtensions=true;
form.maxFileSize=10*1024*1024;
form.multiples=false;
form.parse(req, function (err, fields, files) {
res.write('File uploaded');
res.end();
});
});
module.exports = router;
Download service
var express = require('express');
var router = express.Router();
var express = require('express');
router.get('/', function(req, res, next) {
var file = './file/myOutput.txt';
var name = 'ENC.txt'
res.download(file, name);
});
module.exports = router;
Now i need to make this two service as one?
var express = require('express');
var formidable = require('formidable');
var app=express();
async function calculation(parameters)
{
if(parameters)
{
//Here you can do calculation depending upon parameter values
}
else
{
//Display error or as per your choice
}
}
app.get('/',function(req,res){
res.sendFile(__dirname+'/index.html');
});
async function cal(res,file,form)
{
try{
const data = await calculation(true)
if(data){
res.set({
'Location' : __dirname+'/index.html',
});
res.download( __dirname+file.name);
}
}
catch(error)
{
console.log(error);
}
}
app.post('/',function (req,res){
var form = new formidable.IncomingForm();
form.parse(req);
form.on('fileBegin',function(name,file){
file.path = __dirname+file.name;
console.log("Uploading");
});
form.on('file',
function(name,file)
{
console.log('Uploaded ',file.name);
cal(res,file);
});
});
Hope it helps

nodejs - Express request shape zip from geoserver return text

I am requesting a geoserver from express (node.js) for getting shape zip in wfs service, but I just got text.
var express = require('express');
var router = express.Router();
var fs = require('fs');
var request = require("request");
var DOWNLOAD_DIR = './downloads/';
router.get('/', function(req, res, next) {
var file_url='https://geo.gob.bo/geoserver/aasana/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&typeName=aerodromos&outputFormat=shape-zip';
request(file_url, function(err, resp, body) {
console.log('res',res);
console.log('body',body);
if(!err){
var file = fs.createWriteStream(DOWNLOAD_DIR + 'aerodromos');
var buff = new Buffer(body);
file.write(buff,function(err){
console.log(err);
});
file.end();
console.log(' downloaded to ' + DOWNLOAD_DIR);
}else{
console.log("No results error.",err);
}
});
res.render('index', { title: 'descargado' });
});
module.exports = router;
I am trying to put into a file zip but I cant open it.
you need to set encoding to null which will be treated as buffer rather than string in your case
request({url: file_url, encoding: null}, function(err, resp, body) {

NodeJS Express enumerate files in a folder

Sorry, I'm new with NodeJS Express. I want to get all files from a folder. I tried the following but don't work, test is always empty string:
var express = require('express');
var router = express.Router();
var fs = require('fs');
router.get('/', function(req, res, next) {
var test = '';
const testFolder = './public/images';
fs.readdir(testFolder, (err, files) => {
test = files[0];
})
res.render('index', { title: 'Express', file: test });
});
Basically, I want to get all filenames from public images folder.
Problem here is res.render() will be executed before test is assigned to files[0], because the fs.readdir is asynchronous process. Before your callback is called res.render is excuted. And also, if you are trying to get all files from the folder you should pass files array. Please take a look at this for more info. You might wanna try the below code.
var express = require('express');
var router = express.Router();
var fs = require('fs');
router.get('/', function(req, res, next) {
var test = '';
const testFolder = './public/images';
fs.readdir(testFolder, (err, files) => {
// test = files[0]; this will assign test to the first element of the array of file
test = files;
res.render('index', { title: 'Express', file: test });
})
});

Resources