How to do csv file export and download on request [duplicate] - node.js

How can I download a file that is in my server to my machine accessing a page in a nodeJS server?
I'm using the ExpressJS and I've been trying this:
app.get('/download', function(req, res){
var file = fs.readFileSync(__dirname + '/upload-folder/dramaticpenguin.MOV', 'binary');
res.setHeader('Content-Length', file.length);
res.write(file, 'binary');
res.end();
});
But I can't get the file name and the file type ( or extension ). Can anyone help me with that?

Update
Express has a helper for this to make life easier.
app.get('/download', function(req, res){
const file = `${__dirname}/upload-folder/dramaticpenguin.MOV`;
res.download(file); // Set disposition and send it.
});
Old Answer
As far as your browser is concerned, the file's name is just 'download', so you need to give it more info by using another HTTP header.
res.setHeader('Content-disposition', 'attachment; filename=dramaticpenguin.MOV');
You may also want to send a mime-type such as this:
res.setHeader('Content-type', 'video/quicktime');
If you want something more in-depth, here ya go.
var path = require('path');
var mime = require('mime');
var fs = require('fs');
app.get('/download', function(req, res){
var file = __dirname + '/upload-folder/dramaticpenguin.MOV';
var filename = path.basename(file);
var mimetype = mime.lookup(file);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);
var filestream = fs.createReadStream(file);
filestream.pipe(res);
});
You can set the header value to whatever you like. In this case, I am using a mime-type library - node-mime, to check what the mime-type of the file is.
Another important thing to note here is that I have changed your code to use a readStream. This is a much better way to do things because using any method with 'Sync' in the name is frowned upon because node is meant to be asynchronous.

Use res.download()
It transfers the file at path as an “attachment”. For instance:
var express = require('express');
var router = express.Router();
// ...
router.get('/:id/download', function (req, res, next) {
var filePath = "/my/file/path/..."; // Or format the path using the `id` rest param
var fileName = "report.pdf"; // The default name the browser will use
res.download(filePath, fileName);
});
Read more about res.download()

For static files like pdfs, Word docs, etc. just use Express's static function in your config:
// Express config
var app = express().configure(function () {
this.use('/public', express.static('public')); // <-- This right here
});
And then just put all your files inside that 'public' folder, for example:
/public/docs/my_word_doc.docx
And then a regular old link will allow the user to download it:
My Word Doc

Here's how I do it:
create file
send file to client
remove file
Code:
let fs = require('fs');
let path = require('path');
let myController = (req, res) => {
let filename = 'myFile.ext';
let absPath = path.join(__dirname, '/my_files/', filename);
let relPath = path.join('./my_files', filename); // path relative to server root
fs.writeFile(relPath, 'File content', (err) => {
if (err) {
console.log(err);
}
res.download(absPath, (err) => {
if (err) {
console.log(err);
}
fs.unlink(relPath, (err) => {
if (err) {
console.log(err);
}
console.log('FILE [' + filename + '] REMOVED!');
});
});
});
};

In Express 4.x, there is an attachment() method to Response:
res.attachment();
// Content-Disposition: attachment
res.attachment('path/to/logo.png');
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png

'use strict';
var express = require('express');
var fs = require('fs');
var compress = require('compression');
var bodyParser = require('body-parser');
var app = express();
app.set('port', 9999);
app.use(bodyParser.json({ limit: '1mb' }));
app.use(compress());
app.use(function (req, res, next) {
req.setTimeout(3600000)
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept,' + Object.keys(req.headers).join());
if (req.method === 'OPTIONS') {
res.write(':)');
res.end();
} else next();
});
function readApp(req,res) {
var file = req.originalUrl == "/read-android" ? "Android.apk" : "Ios.ipa",
filePath = "/home/sony/Documents/docs/";
fs.exists(filePath, function(exists){
if (exists) {
res.writeHead(200, {
"Content-Type": "application/octet-stream",
"Content-Disposition" : "attachment; filename=" + file});
fs.createReadStream(filePath + file).pipe(res);
} else {
res.writeHead(400, {"Content-Type": "text/plain"});
res.end("ERROR File does NOT Exists.ipa");
}
});
}
app.get('/read-android', function(req, res) {
var u = {"originalUrl":req.originalUrl};
readApp(u,res)
});
app.get('/read-ios', function(req, res) {
var u = {"originalUrl":req.originalUrl};
readApp(u,res)
});
var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + server.address().port);
});

you can use res.sendFile()... the Sample-download.xlsx should be in the same directory as this function.
const downloadFile = (req,res) => {
var options = {
root: path.join(__dirname),
};
let fileName = "Sample-download.xlsx";
res.sendFile(fileName, options, function (err) {
if (err) {
console.log(err);
return res.status(500).json({ success: false, message: "internal server error. please try again later" });
} else {
console.log("Sent:", fileName, "at", new Date().toString());
}
});
}

Related

Nodejs - Video streaming problems

I'm having some problems when trying to stream videos in nodejs. When I tried just pass the video path to the source/video html tag, it doenst worked. Then, I realized that problably I would have to stream the video.
The problem is: When I stream the video, I just get the video being played in the browser, as a direct link to some downloaded video, not the renderized page with some data(video title and path).
I wanna render the page and then run the video.
When I render, I receive the error: "Can't set headers after they're sent".
My code:
const express = require('express')
const multer = require('multer')
const moment = require('moment')
const uuidv4 = require('uuid/v4');
const bodyParser = require('body-parser')
const fs = require('fs')
const videoLib = require('node-video-lib')
const app = express()
const db = require('./db')
let Video = require('./models/videoModel')
//***** STAND LIBRARIES CONFIGURATION **********//
app.use(bodyParser.urlencoded({extended:true}))
app.use(bodyParser.json())
app.set('views', 'views')
app.set('view engine', 'ejs')
app.set(db)
//***** MULTER CONFIGURATION ***************//
let storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, './uploads')
},
filename: function(req, file, cb){
let mime = file.mimetype.split('/')[1]
let uuid = uuidv4()
cb(null, uuid + "." + mime)
}
})
function fileFilter(req, file, cb){
const extension = file.mimetype.split('/')[0];
if(extension !== 'video'){
return cb(new Error('Something went wrong. Wrong file format'), false);
}
cb(null, true);
};
var upload = multer({storage:storage, fileFilter: fileFilter})
const uploadHandler = upload.single('video')
function uploadVideo(req, res, next){
uploadHandler(req, res, next, function(err){
if(req.fileValidationError){
res.send('Error when upload')
}
console.log(req.file.filename)
next()
})
}
//******************************************//
function newVideo(req, res){
let videoParams = {title: req.body.title, path: req.file.filename}
Video.create(videoParams, function(err, result){
if(err){
console.log(err)
}
else{
console.log("Video salvo com sucesso")
console.log(result)
res.send(result )
}
})
}
app.get('/videos/:id', function(req, res){
let path = req.params.id
Video.find({path:path}, function(err, result){
if(err){
console.log(err);
}
else{
if (true) {
console.log("The url is:" + req.url);
const path = req.url.split('/')[2]
console.log("Path:" + path);
var file = `./uploads/${path}`
var range = req.headers.range;
fs.stat(file, function(err, stats) {
var total = stats.size;
if(range){
console.log('RANGE: ' + range);
var positions = range.replace(/bytes=/, "").split("-");
var start = parseInt(positions[0], 10);
var end = positions[1] ? parseInt(positions[1], 10) : total - 1;
var chunksize = (end - start) + 1;
console.log(req.url, start, end);
res.writeHead(206, {
"Content-Range": "bytes " + start + "-" + end + "/" + total,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4"
});
fs.createReadStream(file, { start: start, end: end }).pipe(res);
} else {
res.writeHead(200, { 'Content-Length': total, 'Content-Type': 'video/mp4' });
fs.createReadStream(file).pipe(res);
res.render('videos', {videoData:result})//Erro: can't set header after they're sent
}
});
} else {
console.log(req.url + ' (static)');
next();
}
}
})
})
app.get('/', function(req, res){
Video.find({}, function(err, result){
if(err){
console.log(err);
}
else{
console.log();
res.render('home', {videoData:result})
}
})
})
app.post('/upload', uploadVideo, newVideo)
app.listen(3000, ()=>{
console.log("Server running on port 3000")
})
You can't use both
res.writeHead();
and
res.render();
Read more: Error: Can't set headers after they are sent to the client

Express Busboy on File Event not firing

I am trying to make busboy work with my express code, but none of its events are firing,
there are no silly mistakes like non-matching input field names etc.
Here is
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./index');
var liveupload = require('./liveupload');
var app = express();
// view engine setup
app.set('view engine', 'pug');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(__dirname + '/bower_components/dropzone/dist'));
app.use('/', index);
app.use('/liveupload', liveupload);
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found SIR');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
This is desired action : liveupload
var express = require('express');
var router = express.Router();
var Busboy = require('busboy');
router.post('/', process_upload);
function process_upload(req, res, next){
var busboy = new Busboy({ headers: req.headers });
// Listen for event when Busboy finds a file to stream.
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
console.log("In bus boy");
// We are streaming! Handle chunks
file.on('data', function (data) {
// Here we can act on the data chunks streamed.
console.log("Chunk mila");
});
// Completed streaming the file.
file.on('end', function () {
console.log('Finished with ' + fieldname);
});
});
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
console.log('Field [' + fieldname + ']: value: ' + inspect(val));
});
console.log("out of busboy");
res.sendStatus(200);
}
module.exports = router;
And here is the UI which uploads the file.
<script language="JavaScript" type="text/javascript" src="javascripts/jquery.min.js"></script>
<script>
$(function(){
Dropzone.options.himanshu = {
paramName: "file",
maxFilesize: 5,
addRemoveLinks: true,
dictResponseError: 'Server not Configured',
acceptedFiles: "*.*",
init:function(){
var self = this;
// config
self.options.addRemoveLinks = true;
self.options.dictRemoveFile = "Delete";
//New file added
self.on("addedfile", function (file) {
console.log('new file added ', file);
});
// Send file starts
self.on("sending", function (file) {
console.log('upload started', file);
$('.meter').show();
});
// File upload Progress
self.on("totaluploadprogress", function (progress) {
console.log("progress ", progress);
$('.roller').width(progress + '%');
});
self.on("queuecomplete", function (progress) {
$('.meter').delay(999).slideUp(999);
});
// On removing file
self.on("removedfile", function (file) {
console.log(file);
});
}
};
})
</script>
<link href="stylesheets/dropzone.css" rel="stylesheet"/>
<form action="/liveupload" method="post" class="dropzone" id="himanshu" enctype="multipart/form-data" >
<div class="fallback">
<input name="file" type="file" multiple />
</div>
</form>
I have tried numerous ways, but still cant figure out why busboy is not working.
any help will be greatly appreciated
Problem was with liveupload.js
here is corrected code -
var busboy = new Busboy({ headers: req.headers });
// Listen for event when Busboy finds a file to stream.
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log("In bus boy");
// We are streaming! Handle chunks
file.on('data', function(data) {
// Here we can act on the data chunks streamed.
console.log("Chunk mila");
});
// Completed streaming the file.
file.on('end', function() {
console.log('Finished with ' + fieldname);
});
});
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
console.log('Field [' + fieldname + ']: value: ' + inspect(val));
});
busboy.on('finish', function() {
console.log("out of busboy");
res.sendStatus(200);
});
req.pipe(busboy);
}

NodeJS - Server Side File Upload Handler

i'm trying to develop a simple file upload handler.
the only thing that i want is , this app receives a file from client and saves on hdd.
(i don't want to upload a file with nodejs , i just want to receive a file upload post and save it on my hdd)
how can i do this ?
i'm tried this way but , it does not works as expected.
var http = require('http'),
path = require('path'),
os = require('os'),
fs = require('fs');
var Busboy = require('busboy');
http.createServer(function(req, res) {
if (req.method === 'POST') {
try{
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
var fstream = fs.createWriteStream('asdasd');
file.pipe(fstream);
fstream.on('close', function () {
res.writeHead(200, { 'Connection': 'close' });
res.send('upload succeeded!');
});
/*var saveTo = path.join(os.tmpDir(), path.basename(fieldname));
file.pipe(fs.createWriteStream('./output.asdasd'));
fstream.*/
});
busboy.on('finish', function() {
res.writeHead(200, { 'Connection': 'close' });
res.end("That's all folks!");
});
return req.pipe(busboy);
}
catch(err){
console.log('error : ' + err);
res.writeHead(404);
res.end();
}
}
res.writeHead(404);
res.end();
}).listen(4842, function() {
console.log('Listening for requests');
});
I've never used busboy before but the example given over in their GitHub documentation works fine.
let http = require('http'),
path = require('path'),
os = require('os'),
fs = require('fs');
let Busboy = require('busboy');
http.createServer(function (req, res) {
if (req.method === 'POST') {
let busboy = new Busboy({ headers: req.headers });
// handle all incoming `file` events, which are thrown when a FILE field is encountered
// in multipart request
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
// figure out where you want to save the file on disk
// this can be any path really
let saveTo = path.join(os.tmpdir(), path.basename(filename));
// output where the file is being saved to make sure it's being uploaded
console.log(`Saving file at ${saveTo}`);
// write the actual file to disk
file.pipe(fs.createWriteStream(saveTo));
});
busboy.on('finish', function () {
res.writeHead(200, { 'Connection': 'close' });
res.end("That's all folks!");
});
return req.pipe(busboy);
}
res.writeHead(404);
res.end();
}).listen(8000, function () {
console.log('Listening for requests');
});
I've added some comments in the relevant section to make it more clear how it works. If you need more details, just comment below and I'll add them.
Simply use the FS api from node to write data received on file ? :)
https://nodejs.org/api/fs.html#fs_class_fs_writestream
Solved ,
i'm tried it with postman , i changed my mind and tried it with RESTClient , it works successfully now :)

Mailgun attachments not showing up

Using Nodejs, I've been able to temporarily store a file that was uploaded in a form to a location. From there, I wanted to use mailgun-js to send an email with that file attached.
I'm able to get the email to display an attachment, but the attachment (in my test case, I'm uploading a regular png file) will be broken. By broken, I mean this:
I'm not sure what is going on--but I can't seem to find anyone else who had my problem; so I'm sure it's something wrong I've done. I appreciate any and all help.
Edit: If I hardcode the path (i.e. I place an image in a folder and then set the attachment to that path) then it sends the attachment correctly and I can view it no problems.
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var bodyParser = require('body-parser');
var https = require('https');
var fs = require('fs-extra');
var busboy = require('connect-busboy');
var multer = require('multer');
var app = express();
var upload = multer(({ dest: __dirname + '/tmp/' }));
// view engine setup
app.set('port', (process.env.PORT || 5000));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon(path.join(__dirname,'public','images','favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(busboy());
// Used for accessing webpages without the .html extension!
var publicdir = __dirname + '/public';
app.use(function(req, res, next) {
if (req.path.indexOf('.') === -1) {
var file = publicdir + req.path + '.html';
fs.exists(file, function(exists) {
if (exists)
req.url += '.html';
next();
});
}
else
next();
});
app.use(express.static(publicdir));
//end .html extension removal
var type = upload.single('file');
app.post('/submit', type, function(req, res, next) {
console.log("____ Clicked submit ____");
//whether or not this form will carry an attachment
var hasAttachment = (req.body.attachment == '') ? false : true;
//path of file
var target_path; //actual image
var tmp_path;
var name = req.body.name;
var email = req.body.email;
var subject = req.body.subject;
var message = req.body.message;
//if there is an attachment, handle getting the file
if (hasAttachment) {
tmp_path = req.file.path;
//The original name of the uploaded file stored in the variable target_path
target_path = __dirname + '/tmp/' + req.file.originalname;
//A better way to copy the uploaded file.
var src = fs.createReadStream(tmp_path);
var dest = fs.createWriteStream(target_path);
src.pipe(dest);
}
//Use validator to sanitize for valid emails
var validator = require('validator');
if (!validator.isEmail(email)) {
console.log("Not a valid email");
res.end();
return;
}
//Mailgun api stuff
var api_key = 'redacted';
var domain = 'redacted';
var mailgun = require('mailgun-js')({
apiKey: api_key,
domain: domain
});
//data for mailgun (to, from, name, etc.)
var data;
if (hasAttachment) {
console.log(target_path);
data = {
from: email,
to: 'myEmail#gmail.com',
subject: subject + ' - ' + name,
text: message,
attachment: target_path
};
} else {
data = {
from: email,
to: 'myEmail#gmail.com',
subject: subject + ' - ' + name,
text: message
};
}
console.log(data);
mailgun.messages().send(data, function (error, result) {
if (error) {
console.error(error);
return;
}
});
console.log("Sent an email!!!");
res.redirect('/contact');
//delete the files after sending the email
if (hasAttachment) {
fs.unlink(target_path);
fs.unlink(tmp_path);
}
});
var server = app.listen(app.get('port'), function() {
//nothing
}); //server closing-bracket
/**
* ERROR HANDLING
*/
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
console.error("***ERROR: " + err.message);
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
send() is asynchronous, and you are deleting the file before it's had a chance to finish.
Instead, delete the files in send callback once you are sure it has finished.
Update:
In addition to the above, your file copy is also happening asynchronously and you are attempting to transfer the file before the copy has completed. So make sure you wait for that:
dest.on("close", function(error, result) {
if (error) {
console.log("COPY ERROR", error);
// TODO: respond with some error result
} else {
mailgun.messages().send(data, function (error, result) {
// delete the files
if (hasAttachment) {
fs.unlink(target_path);
fs.unlink(tmp_path);
}
if (error) {
console.error(error);
// TODO: respond with some error result
} else {
console.log("Sent an email!!!");
res.redirect('/contact');
}
});
}
});
The above change will make your code work.
I presume you are copying the file so that the image will show up properly in the email. (Mailgun infers how to handle the attachment based on its file extension, and Multer's default temp filename doesn't include an extension.)
You can avoid doing the copy altogether by configuring Multer to retain the file extension.
https://github.com/expressjs/multer#storage

Store the uploaded files into file system in Express Js

I am new to nodejs and want to know how to put a file into my system backend or even upload it to S3 etc.
Here are the file object:
req.body { homeColor: 'black',
guestColor: 'white',
thirdColor: 'red',
file:
{ webkitRelativePath: '',
lastModifiedDate: '2014-05-05T02:26:11.000Z',
name: '2014-05-05 10.26.11.jpg',
type: 'image/jpeg',
size: 1310720 },
title: 'tfuyiboinini' }
How to handle req.body.file so that it can be physically saved?
Please help and thanks!
long story short
var fs = require('fs');
app.post('/file-upload', function(req, res) {
var tmp_path = req.files.thumbnail.path;
var target_path = './public/images/' + req.files.thumbnail.name;
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.thumbnail.size + ' bytes');
});
});
};
you can read more about it here:
http://www.hacksparrow.com/handle-file-uploads-in-express-node-js.html
First make sure your POST is encoded as enctype="multipart/form-data"....
In Express 4 you need to set the body parser in your server:
var bodyParser = require('dy-parser');
//...
var app = express();
//...
app.use(bodyParser()); // pull information from html in POST
var busboy = require('connect-busboy');
app.use(busboy());
In earlier version of Express you only needed to add the body parser from the framework itself and files will be store on the configured location:
app.use(express.bodyParser({limit: '10mb', uploadDir: __dirname + '/public/uploads' })); // pull information from html in POST
Since version 4 removed support for connect now you need to add your custom support for multipart/form data to parser multi/part POSTs, so you will have to to do something like:
var fs = require('fs');
var busboy = require('connect-busboy');
//...
app.use(busboy());
//...
app.post('/fileupload', function(req, res) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
fstream = fs.createWriteStream(__dirname + '/files/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
});
});
});
This topic already shared the correct answer so might It is helpful.
Also, please find the below solution.
var express = require('express');
var busboy = require('connect-busboy');
var path = require('path');
var fs = require('fs-extra');
var app = express();
app.use(busboy());
app.use(express.static(path.join(__dirname, 'public')));
app.route('/fileupload')
.post(function (req, res, next) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
//Path where image will be uploaded
fstream = fs.createWriteStream(__dirname + '/img/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
console.log("Uploading process finish " + filename);
// res.redirect('back');
});
});
});

Resources