I am creating a node server to upload files using 'express','fs' and 'busboy' module. The server is working as expected but when I cancel the upload before complete, the incomplete file is stored in the filesystem. How can I remove the incomplete file?
var express = require("express"),
fs = require("fs"),
Busboy = require("busboy");
app = express();
app.listen(7000);
app.get("/", display_form);
app.post("/upload", function(req, res) {
var busboy = new Busboy({
headers: req.headers
});
busboy.on("file", function(fieldname, file, filename, encoding, mime) {
var fstream = fs.createWriteStream("./uploads/" + filename);
file.pipe(fstream);
file.on("data", function(chunk) {
console.log(chunk.length);
});
file.on("end", function() {
console("end");
});
fstream.on("close", function() {
fstream.close();
console("fstream close");
});
fstream.on("error", function() {
console("fstream error ");
});
});
busboy.on("finish", function() {
console.log("uploaded");
res.send("file uploaded");
});
busboy.on("error", function() {
console("error busboy");
});
req.pipe(busboy);
});
Thanks for your help and I finally I found a way to this problem. I added under mentioned code snippet and its working fine.
req.on("close", function(err) {
fstream.end();
fs.unlink('./uploads/' + name);
console.log("req aborted by client");
});
I don't know busboy, but you open a stream and never close it.
Why don't you exploit the stream and filename to 'finish' and 'error' and act accordingly?
Example:
busboy.on('error', function() {
fs.unlink('./uploads/' + filename);
console.log('error busboy');
}
Related
I am new in NodeJS. I know we can stream data to the client by using pipe() method.
Here is the snippet of the code
router.get('/archive/*', function (req, res) {
var decodedURI = decodeURI(req.url);
var dirarr = decodedURI.split('/');
var dirpath = path.join(dir, dirarr.slice(2).join("/"));
console.log("dirpath: " + dirpath);
var archive = archiver('zip', {
zlib: {level: 9} // Sets the compression level.
});
archive.directory(dirpath, 'new-subdir');
archive.on('error', function (err) {
throw err;
});
archive.pipe(res)
archive.on('finish', function () {
console.log("finished zipping");
});
archive.finalize();
});
when I use a get request the zipped file downloaded but without any extension. I know its because I am piping a writestream into the response. Is there anyway pipe it with a .zip extension ? Or How can I send the zip file without building the zip file in HDD ?
You can use res.attachment() to both set the filename of the download, and also its mime-type:
router.get('/archive/*', function (req, res) {
res.attachment('archive.zip');
...
});
One of the ways is to change Headers before piping,
res.setHeader("Content-Type", "application/zip");
res.setHeader('Content-disposition' ,'attachment; filename=downlaod.zip');
For the Given Code,
router.get('/archive/*', function (req, res) {
var decodedURI = decodeURI(req.url);
var dirarr = decodedURI.split('/');
var dirpath = path.join(dir, dirarr.slice(2).join("/"));
var output = fs.createWriteStream(__dirname + '/7.zip');
var archive = archiver('zip', {
zlib: {level: 9} // Sets the compression level.
});
archive.directory(dirpath, 'new-subdir');
archive.on('error', function (err) {
throw err;
});
res.setHeader("Content-Type", "application/zip");
res.setHeader('Content-disposition' ,'attachment; filename=downlaod.zip');
archive.pipe(res);
archive.finalize();
});
I would like to move a small image from one server to another (both running node). As I search, I haven't found enough. This post remains unanswered.
As I started experimenting I wrote the following to the first server :
app.post("/move_img", function(req, res) {
console.log("post handled");
fs.readFile(__dirname + "/img_to_move.jpg", function(err, data) {
if (err) throw err;
console.log(data);
needle.post(server2 + "/post_img", {
data: data,
name : "test.jpg"
}, function(result) {
console.log(result);
res.send("ok");
});
});
});
This part seems to be working as I could be writing the data in the same server (using fs.writeFile) recreate the img.
Now as I am trying to handle the post in the other server I have a problem.
Server2:
app.post('/post_img', [ multer({ dest: './uploads/images'}), function(req, res) {
console.log("body ",req.body) // form fields
console.log("files ",req.files) // form files
res.send("got it");
}]);
This way i get an empty object in the files and the following in the body: { 'headers[Content-Type]': 'application/x-www-form-urlencoded', 'headers[Content-Length]': '45009' }
I think I could use busboy as an alternative but I can't make it to work. Any advice, tutorial would be welcome.
I solved my problem by using the following code,
server1 (using needle) :
app.post("/move_img", function(req, res) {
console.log("post handled")
var data = {
image:{
file: __dirname + "/img_to_move.jpg",
content_type: "image/jpeg"}
}
needle.post(server2 + "/post_img", data, {
multipart: true
}, function(err,result) {
console.log("result", result.body);
});
})
Server 2:
app.use('/post_img',multer({
dest: '.uploads/images',
rename: function(fieldname, filename) {
return filename;
},
onFileUploadStart: function(file) {
console.log(file.originalname + ' is starting ...')
},
onFileUploadComplete: function(file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
}
}));
app.post('/post_img', function(req, res) {
console.log(req.files);
res.send("File uploaded.");
});
An alternative for the server 1 is the following (using form-data module):
var form = new FormData();
form.append('name', 'imgTest.jpg');
form.append('my_file', fs.createReadStream(__dirname + "/img_to_move.jpg"));
form.submit(frontend + "/post_img", function(err, result) {
// res – response object (http.IncomingMessage) //
console.log(result);
});
I'd simply read your file from the first server with the function readFile() and then write it to the other server with the function writeFile().
Here you can see use of both functions in one of my servers.
'use strict';
const express = require('express');
const multer= require('multer');
const concat = require('concat-stream');
const request = require('request');
const router = express.Router();
function HttpRelay (opts) {}
HttpRelay.prototype._handleFile = function _handleFile (req, file, cb) {
file.stream.pipe(concat({ encoding: 'buffer' }, function (data) {
const r = request.post('/Endpoint you want to upload file', function (err, resp, body) {
if (err) return cb(err);
req.relayresponse=body;
cb(null, {});
});
const form = r.form();
form.append('uploaded_file', data, {
filename: file.originalname,
contentType: file.mimetype
});
}))
};
HttpRelay.prototype._removeFile = function _removeFile (req, file, cb) {
console.log('hello');
cb(null);
};
const relayUpload = multer({ storage: new HttpRelay() }).any();
router.post('/uploadMsgFile', function(req, res) {
relayUpload(req, res, function(err) {
res.send(req.relayresponse);
});
});
module.exports = router;
see multer does all the tricks for you.
you just have to make sure you use no middle-ware but multer to upload files in your node starting point.
Hope it does the tricks for you also.
In below code, only finish event called.
var Busboy = require('connect-busboy');
app.use(Busboy());
app.post('/fileupload', function(req, res) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('error', function(err){
console.log(err);
});
req.busboy.on('field', function(fieldname, val, valTruncated, keyTruncated) {
console.log("fieldname: " + fieldname);
});
req.busboy.on('file', function (fieldname, file, filename) {
console.log("filename: " + filename);
fstream = fs.createWriteStream(__dirname + '/files/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
console.log("fileupload end");
});
});
req.busboy.on('finish', function() {
console.log('Done parsing form!');
});
});
The reason why you're not seeing any data is because you're already using the multer module which also parses multipart/form-data requests, saving files to disk. If you're not using multer and want to use busboy manually as you show in your code, you will need to remove the app.use(multer()); line.
I have request handler to send file from MongoDB (GridFS) to client like below, but it use data variable so content is in memory. I need to make this in streaming mode and send file in chunks to client. I can't regognize how to pipe buffer to response. Look at second code - it doesn't work, but show something what i need.
Maybe it is useful: Data in GridFS is Base64 encoded, but may be changed if streaming can be more efficient.
In-Memory version
router.get('/get/:id', function(req,res){
getById(req.params.id, function(err, fileId){
new GridStore(db, fileId, "r").open(function(err, gridStore) {
res.set('Content-Type', gridStore.contentType);
var stream = gridStore.stream(true);
var data = '';
stream.on("data", function(chunk) {
data += chunk;
});
stream.on("end", function() {
res.send(new Buffer(data, 'base64'));
});
});
});
});
Streaming mode version
router.get('/get/:id', function(req,res){
getById(req.params.id, function(err, fileId){
new GridStore(db, fileId, "r").open(function(err, gridStore) {
res.set('Content-Type', gridStore.contentType);
var stream = gridStore.stream(true);
stream.on("data", function(chunk) {
new Buffer(chunk, 'base64').pipe(res);
});
stream.on("end", function() {
res.end();
});
});
});
});
Update
I think I'm close to resolve this. I found this works, but does't decode from Base64:
new GridStore(db, fileId, "r").open(function(err, gridStore) {
res.set('Content-Type', gridStore.contentType);
gridStore.stream(true).pipe(res);
});
exports.sendFile = function(db, res, fileId) {
var grid = require('gridfs-stream');
var gfs = grid(db, mongoose.mongo);
var on_error = function(){
res.status(404).end();
};
var readstream = gfs.createReadStream({
filename: fileId,
root: 'r'
});
readstream.on('error', function(err) {
if (('\'' + err + '\'') === '\'Error: does not exist\'') {
return on_error && on_error(err);
}
throw err;
});
return readstream.pipe(res);
}
I found a solution, but think that can be better. I use base64-stream module to decode Base64 stream. Solution below:
router.get('/get/:id', function(req,res){
getById(req.params.id, function(err, fileId){
new GridStore(db, fileId, "r").open(function(err, gridStore) {
res.set('Content-Type', gridStore.contentType);
gridStore.stream(true).pipe(base64.decode()).pipe(res);
});
});
});
stream.on("data", function(chunk) {
res.send(chunk.toString('utf8'));
});
i want to develope and application in node.js where i shud b able to upload a video in my page and store a link to that video in database(mongodb).when i click //to the link the vedio should get displayed.also i shud b able to display all the //video's uploaded in the page.I tried to code to upload phot
//new show photo code
app.get('/photos', function(req, res) {
photos.list(function(err, photo_list) {
res.render('photos/index', {locals : {
photos: photo_list
}});
});
});
app.get('/photos/new', function(req, res){
res.render('photos/new', {
locals: {
title: 'New File Upload'
}
});
});
app.post('/photos', function(req, res) {
req.setEncoding('binary');
var parser = multipart.parser();
parser.headers = req.headers;
var ws;
parser.onpartBegin = function(part) {
consol.log('inside begin');
ws = fs.createWriteStream(__dirname + '/static/upload/photos.' + part.filename)
ws.on('error', function(err) {
throw err;
});
};
parser.onData = function(data) {
ws.write(data);
};
parser.onPartEnd = function() {
ws.end();
parser.close();
console.log('file successfully uploaded');
res.redirect('/photos');
};
req.on('data', function(data) {
console.log('shud not go here');
parser.write(data);
});
});
//can any one send me the code for the same or else find were i am doing //wrong.....answer immediately required....
You should use formidable for file uploads in Node.js, it's a widely used library for such a thing.