I have an express get route that downloads a CSV file in the browser. That part works fine, but now I want to delete the file using fs.unlink after it is downloaded because it is being stored on the host os in the temporary directory and they build up.
If I try to run the code snipped below, it cannot complete the download because it gets deleted by unlink before it can process (I think).
router.get('/downloadCsv', function(req, res, next) {
res.download(downloadCsvPath);//download file
fs.unlink(downloadCsvPath, (err) => {//delete file from server os
if (err) {
console.error(err);
} else {
console.log('removed: ' + downloadCsvPath);
}
});
});
It gives this error:
Error: ENOENT: no such file or directory, stat '/var/folders/fw/03jxpm311vs548bvf9g_1vxm0000gq/T/<filename>.csv'
As a workaround, I added a 3 second timeout to let the file download first, then delete:
router.get('/downloadCsv', function(req, res, next) {
res.download(downloadCsvPath);//download file
setTimeout(() => {
fs.unlink(downloadCsvPath, (err) => {
if (err) {
console.error(err);
} else {
console.log(downloadCsvPath);
}
});
}, 3000);
});
This works, I get the file downloaded and then it gets deleted from the temporary directory.
But, if connection was poor and it takes longer than 3 seconds, it would probably fail again. There has got to be a better way to run this fs.unlink block of code only once the res.download finishes. I am new to express js so I don't know how to do this. I want to do something like:
res.download(path).then(() => {
//do something
});
But it does not offer this.
I want to run a function after my expressjs res.download, but I do not know a way other than setTimeout
As per Express documentation, res.download() can accept a callback function, which is invoked when the transfer is complete or when an error occurs:
router.get('/downloadCsv', (req, res, next) => {
res.download(downloadCsvPath, (err) => {
if (err) {
// Handle error, but keep in mind the response may be partially-sent
// so check res.headersSent
} else {
fs.unlink(downloadCsvPath, (err) => {
if (err) {
console.error(err);
} else {
console.log(downloadCsvPath);
}
});
}
});
});
Here is the link to the relevant section in the Express documentation.
Hope this helps.
Related
app.delete("/tm/v1/tasks", (req,res) => {
Task.findOneAndDelete(req.body.id, (err, car) => {
if (err){
res.status(500).json({msg: error});
}
res.status(200).json({tasks});
})
});
The above isn't working and is giving an error 404. any ideas?
please check if you have are using correct url
we can add body to delete request in postman or curl but its not possible to pass body in javascript, dart (http package), etc.
you can rewrite function as
app.post('/tm/v1/delete-tasks', (req, res) => {
// write your code here...
});
I'm trying to get access to a pdf from a Google Drive. Whether this access is downloading or viewing, it doesn't really matter, it just needs to be available.
I am using Javascript and NodeJS, with express and google drive api.
I have the following function below which downloads a pdf. But silly me thought this was correct because it worked locally. Then when I deployed it I realised the target filepath no longer makes sense.
function downloadDoc (sourceID, targetName, callback) {
const dest = fs.createWriteStream(`${os.homedir()}/downloads/`+targetName);
drive.files.get(
{sourceID, alt: 'media'},
{responseType: 'stream'},
(err, res) => {
if (err) {
console.error(err);
}
res.data.on('end', () => {
console.log('Done downloading file.');
callback();
})
.on('error', err => {
console.error('Error downloading file.');
throw err;
})
.pipe(dest);
});
}
So what I need to do, is take the data (or response?) from this function and send it over to client side. I assume this is simple to do but, being a simple man, I find myself stuck. I have written this, with the intention that a user can click a link on client side, requesting this URL and calling the function to download the pdf.
app.get('/download_pdf', (req, res) => {
downloadDoc(documentID, 'docName.pdf', ()=>{
console.log("downloaded pdf");
});
res.end();
});
I'm thinking I need to change the argument provided to pipe() since obviously I can't use the filepath.
Similar questions I've checked:
Display Pdf in browser using express js
How to send a pdf file from Node/Express app to the browser
Send pdf via express to js client and download
While these questions are very related to this, I think my issue is due to a lack of understanding of callbacks or requests/responses. I want to learn this properly - not just ask for answers - but as it is, I'm becoming very pressed for time and need a solution soon.
You should be able to simply pipe the returned readable stream to the express res object (which is a writeable stream):
app.get('/download_pdf', (req, res) => {
drive.files.get({
fileId: "your-file-id-here",
alt: 'media'
})
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(res);
});
Edit:
as mentioned here, drive.files.get does return a promise. So you need to change it to:
app.get('/download_pdf', (req, res) => {
drive.files.get({
fileId,
alt: 'media'
}, {
responseType: 'stream'
}).then(response => {
response.data
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(res);
});
});
So I figured out a way. I'm not sure if this is bad practice but it seems to work. I distinguished between the two response objects by referring to one as response and one as res.
app.get('/download_pdf', (req, res) => {
const docId = req.query.id;
drive.files.get({
fileId: docId,
alt: 'media'
}, {
responseType: 'stream'
}).then(response => {
response.data
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(res);
});
});
Posting this in the event that somebody else has a similar issue.
I want to post an image to server.But before that I want to make sure that directory is create, before placing an image to a correct folder.The folder that I want to create is year/month/day/[image]. I am able to generate the folder on my local PC, but when I want to apply on the server, an error message is displayed and the folder is not created.I don't know what mistake that I have made, I hope someone can help me solve this problem.
Thank you in advance.
PWD
ERROR
return binding.mkdir(pathModule._makeLong(path), Error: ENOENT: no
such file or directory, mkdir
'/home/eis/development/eis-api-dev/picture/2020/06/01/'
CODE
var storage = multer.diskStorage({
destination: function (req, file, cb) {
///output: home/eis/development/eis-api-dev/picture/2020/06/01/
const dir = path.join(__dirname,_const.IMAGE_FILE_PATH+_const.generateImagePath(null,null,null));
console.log("path:"+dir);
fs.exists(dir,exists =>{
if(!exists){
//mkdirp.sync(dir);
return fs.mkdirSync(dir,{recursive: true},error => cb(error,dir));
}
return cb(null,dir)
});
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
try to create using mkdirp
if (!fs.existsSync(directoryPath)){
mkdirp(directoryPath, function (err) {
if (err) {
console.log("Error Creating Directory "+directoryPath);
}
else {
console.log("Creating Directory "+directoryPath);
}
}
I just have to upgraded latest nodejs version and its worked.
To create a directory asynchronously
const fs = require('fs');
const path = 'newfolder/xyz/';
fs.exists(path, exists => {
if (exists) {
console.log('The directory exists...!!');
}
else {
fs.mkdir(path, { recursive: true }, (error) => {
console.log(error);
if (error)
// print or display your error
else {
return path;
}
});
}
});
I need your help.
I want to get the public IP address of my Beaglebone via ifconfig.me.
If I have an existing internet connection it works fine. If I don't have an internet connection the request should be aborted.
Here is my code:
function publicIP_www(callback){
try{
exec('curl ifconfig.me',{timeout:3000}, function(error, stdout, stderr){
callback(stdout); });
}
catch (err){
callback("000.000.000.000");
}
}
The returned IP address is then displayed on a web site in the browser.
If there is no internet connection, the browser calculates forever. It seems as if the call exec ...... is not terminated.
I'm looking forward to your support and hope that someone can tell me what I'm doing wrong.
best regards Hans
It's difficult to predict why it is in your case not working, due to not to be able see your code. But you can try next that works fine. Of Course it's dirty, just is an example.
Next code is for index.js file of the "Node.js Express App + Jade" project that was created from template in WebStorm IDE.
const util = require('util');
const exec = util.promisify(require('child_process').exec);
....
....
router.get('/', async function(req, res, next) {
try {
const {stdout, stderr} = await exec('curl ifconfig.me');
res.render('index', { title: stdout});
}
catch (err) {
res.render('index',{ title: "000.000.000.000"});
}
});
OR use
const util = require('util');
const exec = require('child_process').exec;
function publicIP_www(callback){
exec('curl ifconfig.me',{timeout:3000}, function(error, stdout, stderr){
if (error) {
return callback("000.000.000.000");
}
callback(stdout);
});
}
router.get('/', function(req, res, next) {
publicIP_www((title) => {
res.render('index', { title });
})
});
In my app.js file I had the code below and it worked as intended. I need to clean up my code, so I moved it to it's own route at routes/random and it no longer works because I get an error that states: "http://localhost:1337/random/1/1/testing 404 (Not Found)" and I am not sure why. My original code was in my app.js file when it was working was:
app.get('/random/:room/:userId/:message', function(req, res) {
fs.appendFile(room.number.toString(), req.params.message, function(err) {
if (err) {
console.log('error writing messages to file');
};
fs.readFile('./' + room.number, 'utf-8', function(err, data) {
if (err) {
if (err.fileNotFound) {
return this.sendErrorMessage('can\'t find the file, you linked it incorrectly');
}
console.log('error reading message file');
};
if (req.params.userId == 1) {
messages.user1.push(data);
} else {
messages.user2.push(data);
};
console.log(messages);
res.send(data);
fs.unlink(req.params.room, function(err) {
});
});
});
});
the new code includes the following for app.js
var express = require('express');
var app = express();
var fs = require('fs');
var random = require('./routes/random');
app.use('/random/', random);
app.use(express.static('public'));
app.use(express.static('public/js'));
app.use(express.static('public/images'));
and after I moved it, the route code is:
var express = require ('express');
var fs = require ('fs');
var random = express.Router();
random.get('/random/:room/:userId/:message', function(req, res) {
fs.appendFile(room.number.toString(), req.params.message, function(err) {
if (err) {
console.log('error writing messages to file');
};
fs.readFile('./' + room.number, 'utf-8', function(err, data) {
if (err) {
if (err.fileNotFound) {
return this.sendErrorMessage('can\'t find the file, you linked it incorrectly');
}
console.log('error reading message file');
};
if (req.params.userId == 1) {
messages.user1.push(data);
} else {
messages.user2.push(data);
};
console.log(messages);
res.send(data);
fs.unlink(req.params.room, function(err) {
});
});
});
});
module.exports = random;
Can anyone explain what I have done wrong that won't allow it to find the file?
In your code you are defining a route called random\random... in random.js, delete first random there, because middleware(app.use..) will direct all routes with /random to your router instance.
Your router is handling a url that starts with /random, and you attach this to your app under the path /random/. Remove one or the other (preferebly, the one inside the router).
I was able to fix it. Both comments above are correct, but it still was throwing errors due to my variables being undefined. I figured it out though so I am closing this question. Thank you both