Server Request Interrupted on Heroku when using Busboy - node.js

I am using Busboy to transfer files in my Nodejs app since it supports chunked uploads. When the files are just small sized images upload is working fine but once I'm about uploading videos sometimes it works sometimes it doesn't work and all I keep seeing on my Heroku logs is
H18-Server Request Interrupted.
This is quite draining.
Here is my code:
path = require('path'),
os = require('os'),
fs = require('fs');
var Busboy = require('busboy');
http.createServer(function(req, res) {
if (req.method === 'POST') {
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
var saveTo = path.join(os.tmpDir(), path.basename(fieldname));
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');
});
How can this be resolved?

Related

How can I serve a GZipped file with NodeJS?

I created simple app used angular elements and http node server. To optimize bundle size i just convert the resulting js file to gz format with current command:
"postbuild": "cat dist/cs6-user-widget/{runtime,polyfills,polyfills-es5,scripts,main}.js | gzip > webcomponent/user-widget.js.gz"
The file is created correctly, but i cannot serve this type of content with my node server:
const http = require('http');
const fs = require('fs');
const hostname = 'localhost';
const port = 4202;
http.createServer((request, response) => {
var contentType = 'text/html';
var filePath = './' + request.url;
fs.readFile(filePath, function(error, content) {
if (error) {
fs.readFile('./index.html', function(error, content) {
response.writeHead(200, { 'content-encoding': 'gzip', 'Content-Type': contentType });
return response.end(content, 'utf-8');
});
} else {
response.writeHead(200, { 'content-encoding': 'gzip', 'Content-Type': contentType });
return response.end(content, 'utf-8');
}
});
});
Can You help me to correctly implement node part?
First, please see this answer
If you still want to use node, here is a simple example:
const express = require("express");
const gzipStatic = require("connect-gzip-static");
const app = express();
app.use(gzipStatic(__dirname));
app.listen(4000);

Is there a way to provide file for download using only Node without using express like below?

app.get('/download', function(req, res){
const file = `${__dirname}/upload-folder/dramaticpenguin.MOV`;
res.download(file); // Set disposition and send it.
});
Here's a super simple example that should give you a start on how to implement this without express:
const http = require('http');
const fs = require('fs');
const path = require('path');
const httpServer = http.createServer(requestResponseHandler);
function requestResponseHandler(req, res) {
if (req.url === '/download') {
const file = `${__dirname}/sample-video.mov`;
res.writeHead(200, {
'Content-Type': 'video/quicktime',
'Content-Disposition': 'attachment; filename="sample.mov',
});
fs.createReadStream(file).pipe(res);
}
}
httpServer.listen(3000, () => {
console.log('server is listening on port 3000');
});
Basically all it does is to set the correct content-type and content-disposition headers and the create a read-stream from the mov-file and pipe this stream into the response-object.

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 :)

Encoding Issue with Gridfs-stream, Multiparty Middleware

I am having some problems properly storing and retrieving files with GridFS. Currently, if I submit a .txt file I end up getting the contents of the file back, but if i submit a .doc file, I get a bunch of gibberish (like blackdiamonds with question marks in it).
My end goal is just to be able to submit the file and then allow someone to download the file later on a different request.
Writing Code:
router.post('/jobs/listing/:job/apply', multipartyMiddleware, function(req, res, next){
var myFile = req.files.file;
var conn = mongoose.createConnection('mongodb://localhost/test');
conn.once('open', function () {
var gfs = Grid(conn.db, mongoose.mongo);
var readfile = fs.createReadStream(myFile.path);
var f = readfile.pipe(gfs.createWriteStream({
filename: myFile.name
}));
f.on('close', function(){
console.log('File Added to GRIDFS');
res.end();
});
});
}
Reading Code:
var conn = mongoose.createConnection('mongodb://localhost/test');
conn.once('open', function () {
var gfs = Grid(conn.db, mongoose.mongo);
var readstream = gfs.createReadStream({
filename: req.file //set to desired filename
});
var f = readstream.pipe(res);
});
Any suggestions? I would really appreciate any help you can provide. Thanks.
Edit: Problem had to do with an uploading issue in angular.
Here's a simple implementation that I copied from another developer and modified. This is working for me:
https://gist.github.com/pos1tron/094ac862c9d116096572
var Busboy = require('busboy'); // 0.2.9
var express = require('express'); // 4.12.3
var mongo = require('mongodb'); // 2.0.31
var Grid = require('gridfs-stream'); // 1.1.1"
var app = express();
var server = app.listen(9002);
var db = new mongo.Db('test', new mongo.Server('127.0.0.1', 27017));
var gfs;
db.open(function(err, db) {
if (err) throw err;
gfs = Grid(db, mongo);
});
app.post('/file', function(req, res) {
var busboy = new Busboy({ headers : req.headers });
var fileId = new mongo.ObjectId();
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log('got file', filename, mimetype, encoding);
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: filename,
mode: 'w',
content_type: mimetype,
});
file.pipe(writeStream);
}).on('finish', function() {
// show a link to the uploaded file
res.writeHead(200, {'content-type': 'text/html'});
res.end('download file');
});
req.pipe(busboy);
});
app.get('/', function(req, res) {
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/file" enctype="multipart/form-data" method="post">'+
'<input type="file" name="file"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
});
app.get('/file/:id', function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
if (!file) return res.status(404).send('');
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function(err) {
console.log("Got error while processing stream " + err.message);
res.end();
});
readstream.pipe(res);
});
});
For anyone who ends up with this issue,
I had the same symptoms and the issue was a middleware. This was a gnarly bug. The response was being corrupted by connect-livereload.
Github Issue on busboy
Github Issue on gridfs stream
My response on a Similar Stack Overflow Issue

How to do csv file export and download on request [duplicate]

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

Resources