multer won't recognize files with PUT - node.js

So I just installed node and fire up a little HTTP server with express. I'm trying to upload files with multer and HTTP PUT but it seems as multer can't handle PUTting files.
Doing the same thing with POST works just fine.
This is my main.js:
var express = require('express');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
});
var upload = multer({ storage: storage });
var app = express();
app.get('/', function (req, res) {
res.send('Up and running');
});
app.put('/up/:file', upload.any(), function (req, res, next) {
console.log('files: ' + req.files);
console.log(req.params.file);
res.send('got that');
})
app.post('/up', upload.any(), function (req, res, next) {
res.send('got that');
})
var server = app.listen(8888, function(){
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
Using curl I can POST files just fine, e. g. with curl --form "file=#someFile.jpg" http://localhost:8888/up.
I tried putting a file with curl http://localhost:8888/up/someFile.jpg --upload-file someFile.jpg as well as with curl -i -T someFile.jpg http://localhost:8888/up/someFile.jpg but it just won't work. req.files is always undefined.
Question/TL;DR: Is multer just not capable of accepting files via PUT? How can I receive files per PUT with express? Actually, I don't need express ... a plain node solution would be enough.

Your two forms of curl for sending your PUT request are not sending multipart/form-data bodies, they are sending the raw file contents as the body instead. multer does not support that, as it is expecting multipart/form-data-encoded forms.
To support these raw file uploads, you will need to handle them yourself (e.g. piping the request to disk or wherever). For example:
app.put('/up/:file', function (req, res, next) {
// TODO: optionally validate `req.headers['content-type']`
// TODO: sanitize `req.params.file` before
// using it to create the filename
var filename = req.params.file;
var diskStream = fs.createWriteStream(path.join(__dirname, 'uploads', filename));
req.pipe(diskStream).on('finish', function() {
res.send('got that');
});
});

Related

How to use Node to read PUT file?

I'm trying to replicate the functionality of bashupload.com but using node. I want the simplicity of just doing curl host -T file but I ran into some problems because I can't seem to understand how to read the PUT file. Curl uses a PUT request when you use the -T option, so it has to be PUT.
I tried using packages like multiparty:
receiveAndUploadFile: function (req, res) {
var multiparty = require('multiparty');
var form = new multiparty.Form();
// var fs = require('fs');
form.parse(req, function(err, fields, files) {
console.log('The files', files)
console.log('The fields', fields)
})
res.send("Okay, bye.")
}
But this prints undefined values for files and fields.
I also tried using express-fileupload middleware
app.use(fileUpload({}));
but still, if I try to print req.files then I will get undefined.
Is there any specific way to read the file?
Thanks a lot!
This is my main file, index.js::
const express = require("express");
const path = require("path");
const app = express();
const port = 8080;
const tools = require("./tools");
const fileUpload = require("express-fileupload");
app.use(fileUpload());
app.use(express.static(__dirname + "/assets"));
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname + "/index.html"));
});
app.get("/f", (req, res) => {
res.send("This route is only available as a POST route.");
});
app.put("/f", tools.receiveAndUploadFile);
app.listen(port, () => {
console.log(`Server started listening on port: ${port}`);
});
And the tools.js file:
const fs = require("fs");
const path = require("path");
module.exports = {
receiveAndUploadFile: function (req, res) {
console.log("Files: ", req.files);
res.send("Okay bye");
},
};
This is printing "Files: undefined" to the console.
A PUT and a POST are effectively the same thing. To upload arbitrary data, just read the data stream and write it to a file. Node provides a .pipe method on streams to easily pipe data from one stream into another, for example a file stream here:
const fs = require('fs')
const express = require('express')
const app = express()
const PORT = 8080
app.get('/*', (req, res) => res.status(401).send(req.url + ': This route is only available as a POST route'))
app.put('/*', function (req, res, next) {
console.log('Now uploading', req.url, ': ', req.get('content-length'), 'bytes')
req.pipe(fs.createWriteStream(__dirname + req.url))
req.on('end', function () { // Done reading!
res.sendStatus(200)
console.log('Uploaded!')
next()
})
})
app.listen(8080, () => console.log('Started on :8080'))
If you do a PUT to /file.mp4, it will upload all the data over to the script dir (__dirname) + the URL file path.
via curl, curl http://localhost:8080/ -T hello.txt

Error when uploading files using FilePond and multer (expressjs)

I've written a react app that makes use of the FilePond file uploader but am having trouble getting multer to accept the request from filepond, it always returns a 500 error.
If I use a standard file upload control the request is accepted by the server and the file uploads fine.
Does anyone have any thoughts on what might be causing this?
Thanks
This is my server.js code:
var express = require('express');
var app = express();
var multer = require('multer')
var cors = require('cors');
app.use(cors())
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public')
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' +file.originalname )
}
})
var upload = multer({ storage: storage }).array('file')
app.get('/',function(req,res){
return res.send('Hello Server')
})
app.post('/upload', function(req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
return res.status(500).json(err)
// A Multer error occurred when uploading.
} else if (err) {
return res.status(500).json(err)
// An unknown error occurred when uploading.
}
res.send([req.files[0].filename]);
return res.status(200).send(req.file)
// Everything went fine.
})
});
app.listen(8000, function() {
console.log('App running on port 8000');
});

File uploading in express using multer

I am trying to upload image using multer but getting error,uploads is not a function.Here is my code
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
console.log(req.file);
var file = __dirname + '/' + req.file.filename;
uploads(req.file.path, file, function(err) {
if (err) {
console.log(err);
res.send(500);
} else {
res.json({
message: 'File uploaded successfully',
filename: req.file.filename
});
}
});
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
yourModel.create(req.body,function(err,result){
console.log(result);
});
});
Its quite obvious; uploads is not a function but uplaod is. So use
upload.single('image')
As #Kuldeep said you don't have to the uploads(filePath, file, (err) => {...}) inside the route.
When you are using multer as middleware (the middle function) multer will automatically upload the file and expose the filename, originalName etc to req.file object inside the route
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
// here just write the success or error login
});
Reference You can check here: here
EDIT: The above code will upload the file with hex string as filename without any extension.
In order to add rename function you need to use diskStorage. Here is the code taken from this github issue page.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './images/')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype)); //this is the rename func
});
}
});
var uploads = multer({ storage: storage });
Now you can use the uploads variable as middleware as shown in the above snippet.
I haven't found a great, soup-to-nuts guide on using Multer (the website is just a little lacking for newbies) so here's my stab at it.
After using:
npm install multer --save
to add it to your project.
For me, I wanted to capture files on a specific route, namely:
/customers/:id/upload
So, I went into my customers.js route file and added:
var multer = require('multer');
as well as the code to set up the storage (diskStorage) and filename configuration tweaks:
var storage=multer.diskStorage({
destination: function(req,file,cb){
cb(null,'/uploads/');
},
filename: function(req,file,cb){
cb(null,file.fieldname+'-'+Date.now());
}
});
I could then create the upload middleware object that lets me specify, per route, how I would like Multer to handle file uploads. On the route above, I only want to receive one file with a particular internal filename so my customers.js route file looks like this:
router.post('/:id/targets/upload', upload.single('connections'), function(req,res,next){
console.log("Router:POST: Companies/:_id/upload");
console.log(req.file);
...
});
All of the examples I saw had stuff being added to the app.js file but these seemed a bit awkward and contrived as examples. Every route may have different file handling needs so it just seemed more appropriate, to me, to configure Multer on a per-controller basis. YMMV.

How to get FormData in Express js?

I'm trying to upload a file to my express server. The client code looks like this:
axios.post('localhost:3030/upload/audio/', formData)
And in my express server:
App.use(bodyParser.urlencoded({ extended: true }));
App.use(bodyParser.json());
App.post('/upload/audio/', function uploadAudio(req, res) {
let quality = ['320', '128'];
let file = req.body;
console.log(file)
res.send('Frick')
}
However, even though the mp3 file is sent:
The req.body is empty when logged (note the empty object):
How can I get the formData (and file) in Express.js?
As #Tomalak said body-parser does not handle multipart bodies.
So you need to use some third party module I suggest use awesome module multer
I tried to do your code, hope it can help you
App.post('/upload/audio/', function uploadAudio(req, res) {
var storage = multer.diskStorage({
destination: tmpUploadsPath
});
var upload = multer({
storage: storage
}).any();
upload(req, res, function(err) {
if (err) {
console.log(err);
return res.end('Error');
} else {
console.log(req.body);
req.files.forEach(function(item) {
console.log(item);
// move your file to destination
});
res.end('File uploaded');
}
});
});

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.

Resources