Search code examples
node.jsexpressfile-uploadputmulter

multer won't recognize files with PUT


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.


Solution

  • 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');
      });
    });