Trying to upload a file to a nodejs web service - node.js

I'm trying to create a simple web service in nodejs that accepts a file and saves it.
Here is my code.
var express = require('express');
var app = express();
var fs = require('fs');
var sys = require('sys');
app.listen(8080);
app.post('/upload', function(req, res) {
console.log(req.files);
var fileKey = Object.keys(req.files)[0];
var file = req.files[fileKey];
fs.readFile(file.path, function(err, data) {
fs.writeFile(__dirname, data, function(err) {
res.redirect("back");
});
});
});
I'm using fiddler to upload the file.
console.log(req.files);
gives undefined. An exception is also thrown:
Object.keys called on non-object
Any idea what I may be doing wrong?

You don't seem to be using the bodyParser middleware which is required to parse uploads (amongst other things):
app.use(express.bodyParser());
app.post('/upload', function(req, res) { ... });

Related

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

how to get the values from postman extention "form-data" values

I am using node js with express framework and rest api
for rest api client i am using postman extension with chrome browser
here i am able to get values from option "x-www-form-urlencoded" but i am not able to get values from "form data" i want to get values from "form data" option and also need to upload image file.
please help me any to achieve this. i want to get values from "form data" option and also image. please help me.
Below i have mentioned code what i have used.
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var http = require('http').Server(app);
var mysql = require('mysql');
var util = require('util');
var trim = require('trim');
var validator = require('validator');
var bodyParser = require('body-parser');
var Ingest = require('ingest');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var type = upload.single('recfile');
passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
async = require('async');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/upload', function(req, res){
console.log(req.file); // "form-data" values not able to get here
console.log(req);// "form-data" values not able to get here
console.log('body : '+JSON.stringify(req.body));// "form-data" values not able to get here
});
i didn't set any content type in postman header
app.post('/upload', function(req, res){
console.log('req.headers \n '+JSON.stringify(req.headers));
console.log('req.body.file :- '+req.body.file);
console.log('\n\n req.body :- '+JSON.stringify(req.body));
});
I got the below result for the above code.
req.headers
{"host":"localhost:3001","connection":"keep-alive","content length":"5808","cache-control":"no-cache","origin":"chrome-extension://mkhojklkhkdaghjjfdnphfphiaiohkef","password":"password","user-agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36","username":"User2","content-type":"multipart/form-data; boundary=----WebKitFormBoundaryV4zAIbjEyKYxLRWe","accept":"*/*","accept-encoding":"gzip, deflate","accept-language":"en-US,en;q=0.8","cookie":"connect.sid=s%3Atz4f1ZgJkaAjuDD1sOkMB9rr.Z8EUIyxEcr0EyFQL96v0ExGRidM3SAVTx8IIr52O0OI"}
req.body.file :- undefined
req.body :- {}
Yes the same problem facing me several times and according my experience you do't set the content-type in postman header because it should be undefined and node server automatically set the content type according to requirement. If you set the content-type then you do't get any image and other data in the node server .
You get the image from the req.body.file
you get the other data from req.body
app.use(multipart()) in middleware
Procedure how to use multipart as middleware
var multipart = require('connect-multiparty');
global.app = module.exports = express();
app.use(multipart());
I got solution with help of the below code
var express = require('express');
var router = express.Router();
var util = require("util");
var fs = require("fs");
var formidable = require('formidable');
var path = require('path');
router.post("/upload", function(req, res, next){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
// `file` is the name of the <input> field of type `file`
console.log(files);
console.log(fields);
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
form.on('error', function(err) {
console.error(err);
});
form.on('progress', function(bytesReceived, bytesExpected) {
var percent_complete = (bytesReceived / bytesExpected) * 100;
console.log(percent_complete.toFixed(2));
});
form.on('end', function(fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Location where we want to copy the uploaded file */
var new_location = 'public/images/';
fs.readFile(temp_path, function(err, data) {
fs.writeFile(new_location + file_name, data, function(err) {
fs.unlink(temp_path, function(err) {
if (err) {
console.error(err);
} else {
console.log("success!");
}
});
});
});
});
});
I think you need to use body-parser for this and also need to update your app.js as
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
I was facing same problem I was not able to get form data fields body parser is not enough to get those values. Hitting google searched a lot of stuff about it but nothing works. Here is the solution how I got form data values.
Note: I am using typescript instead of js
Install multer package: npm i multer
Now in app.ts or app.js import accordingly:
import multer from "multer"
Define the multer function
const upload = multer(); // config
After body parser:
app.use(upload.any());

File uploading with Express 4.0: req.files undefined

I'm attempting to get a simple file upload mechanism working with Express 4.0 but I keep getting undefined for req.files in the app.post body. Here is the relevant code:
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
//...
app.use(bodyParser({ uploadDir: path.join(__dirname, 'files'), keepExtensions: true }));
app.use(methodOverride());
//...
app.post('/fileupload', function (req, res) {
console.log(req.files);
res.send('ok');
});
.. and the accompanying Pug code:
form(name="uploader", action="/fileupload", method="post", enctype="multipart/form-data")
input(type="file", name="file", id="file")
input(type="submit", value="Upload")
Solution
Thanks to the response by mscdex below, I've switched to using busboy instead of bodyParser:
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');
});
});
});
The body-parser module only handles JSON and urlencoded form submissions, not multipart (which would be the case if you're uploading files).
For multipart, you'd need to use something like connect-busboy or multer or connect-multiparty (multiparty/formidable is what was originally used in the express bodyParser middleware). Also FWIW, I'm working on an even higher level layer on top of busboy called reformed. It comes with an Express middleware and can also be used separately.
Here is what i found googling around:
var fileupload = require("express-fileupload");
app.use(fileupload());
Which is pretty simple mechanism for uploads
app.post("/upload", function(req, res)
{
var file;
if(!req.files)
{
res.send("File was not found");
return;
}
file = req.files.FormFieldName; // here is the field name of the form
res.send("File Uploaded");
});
1) Make sure that your file is really sent from the client side. For example you can check it in Chrome Console:
screenshot
2) Here is the basic example of NodeJS backend:
const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
app.use(fileUpload()); // Don't forget this line!
app.post('/upload', function(req, res) {
console.log(req.files);
res.send('UPLOADED!!!');
});
It looks like body-parser did support uploading files in Express 3, but support was dropped for Express 4 when it no longer included Connect as a dependency
After looking through some of the modules in mscdex's answer, I found that express-busboy was a far better alternative and the closest thing to a drop-in replacement. The only differences I noticed were in the properties of the uploaded file.
console.log(req.files) using body-parser (Express 3) output an object that looked like this:
{ file:
{ fieldName: 'file',
originalFilename: '360px-Cute_Monkey_cropped.jpg',
name: '360px-Cute_Monkey_cropped.jpg'
path: 'uploads/6323-16v7rc.jpg',
type: 'image/jpeg',
headers:
{ 'content-disposition': 'form-data; name="file"; filename="360px-Cute_Monkey_cropped.jpg"',
'content-type': 'image/jpeg' },
ws:
WriteStream { /* ... */ },
size: 48614 } }
compared to console.log(req.files) using express-busboy (Express 4):
{ file:
{ field: 'file',
filename: '360px-Cute_Monkey_cropped.jpg',
file: 'uploads/9749a8b6-f9cc-40a9-86f1-337a46e16e44/file/360px-Cute_Monkey_cropped.jpg',
mimetype: 'image/jpeg',
encoding: '7bit',
truncated: false
uuid: '9749a8b6-f9cc-40a9-86f1-337a46e16e44' } }
multer is a middleware which handles “multipart/form-data” and magically & makes the uploaded files and form data available to us in request as request.files and request.body.
installing multer :- npm install multer --save
in .html file:-
<form method="post" enctype="multipart/form-data" action="/upload">
<input type="hidden" name="msgtype" value="2"/>
<input type="file" name="avatar" />
<input type="submit" value="Upload" />
</form>
in .js file:-
var express = require('express');
var multer = require('multer');
var app = express();
var server = require('http').createServer(app);
var port = process.env.PORT || 3000;
var upload = multer({ dest: 'uploads/' });
app.use(function (req, res, next) {
console.log(req.files); // JSON Object
next();
});
server.listen(port, function () {
console.log('Server successfully running at:-', port);
});
app.get('/', function(req, res) {
res.sendFile(__dirname + '/public/file-upload.html');
})
app.post('/upload', upload.single('avatar'), function(req, res) {
console.log(req.files); // JSON Object
});
Hope this helps!
Please use below code
app.use(fileUpload());
Just to add to answers above, you can streamline the use of express-fileupload to just a single route that needs it, instead of adding it to the every route.
let fileupload = require("express-fileupload");
...
//Make sure to call fileUpload to get the true handler
app.post("/upload", fileupload(), function(req, res){
...
});
A package installation needs for this functionality, There are many of them but I personally prefer "express-fileupload". just install this by "npm i express-fileupload" command in the terminal and then use this in your root file
const fileUpload = require("express-fileupload");
app.use(fileUpload());
PROBLEM SOLVED !!!!!!!
Turns out the storage function DID NOT run even once.
because i had to include app.use(upload) as upload = multer({storage}).single('file');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './storage')
},
filename: function (req, file, cb) {
console.log(file) // this didn't print anything out so i assumed it was never excuted
cb(null, file.fieldname + '-' + Date.now())
}
});
const upload = multer({storage}).single('file');
I added multer as global middleware before methodOverride middleware,
and it worked in router.put as well.
const upload = multer({
storage: storage
}).single('featuredImage');
app.use(upload);
app.use(methodOverride(function (req, res) {
...
}));
With Formidable :
const formidable = require('formidable');
app.post('/api/upload', (req, res, next) => {
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
res.json({ fields, files });
});
});
https://www.npmjs.com/package/formidable
You can use express-fileupload npm package to decode files like
const fileUpload = require('express-fileupload');
app.use(fileUpload({useTempFile: true}))
Note: I am using cloudinary to upload image
enter image description here
express-fileupload looks like the only middleware that still works these days.
With the same example, multer and connect-multiparty gives an undefined value of req.file or req.files, but express-fileupload works.
And there are a lot of questions and issues raised about the empty value of req.file/req.files.

Avoiding image logging in Express.js

I'm using Express.JS in node, and i saw that in the log file generate by the logger. I would like to avoid the logging of the image, how could I set the type of requests I want to save in the log file?
Thanks!
This should do the trick
var express = require("express");
var logger = express.logger();
var app = express.createServer();
var conditionalLogger = function (req, res, next) {
if (!(/\.(png|jpg|gif|jpeg)$/i).test(req.path)) {
logger(req, res, next);
} else {
next();
}
}
app.use(conditionalLogger);
app.use(express.static("./public"));
app.listen(3456);

Resources