multipart File uploads using NodeJS

44,144

Solution 1

@user568109 and @nick-fishman are correct; you should use the bodyParser middleware for this.

Please see the sample code for a basic file upload form below. (Note: you will need to create an "uploads" directory to store the files.)

file-upload.js:

var express = require("express"),                                                                
    app = express();                                                                             

// tell express to use the bodyParser middleware                                                 
// and set upload directory                                                                      
app.use(express.bodyParser({ keepExtensions: true, uploadDir: "uploads" }));                     
app.engine('jade', require('jade').__express);                                                   

app.post("/upload", function (request, response) {                                               
    // request.files will contain the uploaded file(s),                                          
    // keyed by the input name (in this case, "file")                                            

    // show the uploaded file name                                                               
    console.log("file name", request.files.file.name);                                           
    console.log("file path", request.files.file.path);                                           

    response.end("upload complete");                                                             
});                                                                                              

// render file upload form                                                                       
app.get("/", function (request, response) {                                                      
    response.render("upload_form.jade");                                                         
});                                                                                              

app.listen(3000);

views/upload_form.jade:

doctype 5
html
    head
        title Upload Form
    body
        h1 Upload File
        form(method="POST", action="/upload", enctype="multipart/form-data")
            input(type="file", name="file")
            input(type="submit")

Solution 2

Try use busboy-body-parser to retrieve the request body parameters and the files.

start.js
var bodyParser = require('body-parser');
var busboyBodyParser = require('busboy-body-parser');


// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({
  extended: true
}));

// parse application/json
app.use(bodyParser.json());


//parse multipart/form-data    
app.use(busboyBodyParser());



controllers/someController.js
someAction: function(req,res){
     if(req.method == "POST"){
           res.end(JSON.stringify(req.body)+JSON.stringify(req.files));
     }
}
//{"text":"testx"}{"anexo":{"data":{"type":"Buffer","data":.... }}} 
//req.body = {"text":"testx"}
//req.files = {"anexo":{"data":{"type":"Buffer","data":.... }}} 


views/someController/someAction.html
<form method="post" id="multipart" enctype="multipart/form-data">
    <input type="text" id="text1" name="text" value="testx" />
    <input type="file" id="anexo" name="anexo"  />
    <input type="submit" value="Enviar" />
</form>

To create a file uploaded, you need work if the stream, for example:

/* file props
{  
   "data":{"type":"Buffer","data":.... },
   "fieldname":"anexo",
   "originalname":"images (1).jpg",
   "encoding":"7bit",
   "mimetype":"image/jpeg",
   "destination":"c:\\live\\sources\\uploads\\",
   "filename":"eventclock_images(1)_1443706175833.jpg",
   "path":"c:\\live\\sources\\uploads\\eventclock_images(1)_1443706175833.jpg",
   "size":9986
}
*/

var fileStream = fs.createWriteStream(file.path);
fileStream.write(file.data);
fileStream.end();

fileStream.on('error', function (err) {
    //console.log("error",err);
});
fileStream.on('finish', function (res) {
    //console.log("finish",res);
});     

Solution 3

@user568109 is correct: you need ExpressJS and bodyParser enabled. Do you have a line similar to the following in your configuration?

app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/my/files' }));
Share:
44,144
Matt Hintzke
Author by

Matt Hintzke

Software Engineer @ SkyKick in Seattle, WA. Building modern microservice applications in the Azure Cloud using a .NET, Node and Angular stack

Updated on October 03, 2020

Comments

  • Matt Hintzke
    Matt Hintzke over 3 years

    I am having troubles getting file uploads to work with NodeJS. I am using Dropzone.JS to create a form that sends a POST request to /file-upload here:

    <form action="/file-upload" class="dropzone dragndrop" id="my-awesome-dropzone"></form> 
    

    Then I have a route in app.js:

    app.post('/file-upload', routes.upload);
    

    Then my handler:

    exports.upload = function(req, res){
         console.log(req.files);
         res.send("OK");
    }
    

    However, the upload function here is never called. The server crashes with this error first:

    events.js:69
            throw arguments[1]; // Unhandled 'error' event
                           ^
    Error: Invalid data
        at WriteStream._write (fs.js:1616:31)
        at onwrite (_stream_writable.js:265:14)
        at WritableState.onwrite (_stream_writable.js:94:5)
        at fs.js:1628:5
        at Object.wrapper [as oncomplete] (fs.js:475:5)
        at process._makeCallback (node.js:321:24)
    

    So I am not sure what I should do because it appears that this is not my fault. I followed other tutorials and saw nothing wrong. Also, when I inspect my Network under chrome dev tools, it shows:

    Request URL:http://localhost:3000/file-upload
    **Request Headers**
    Accept:application/json
    Cache-Control:no-cache
    Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryMmLSkbfQskfIcjfE
    Origin:http://localhost:3000
    Pragma:no-cache
    Referer:http://localhost:3000/
    User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
    X-File-Name:Screenshot from 2013-03-20 12:23:42.png
    X-Requested-With:XMLHttpRequest
    **Request Payload**
    ------WebKitFormBoundaryMmLSkbfQskfIcjfE
    Content-Disposition: form-data; name="file"; filename="Screenshot from 2013-03-20 12:23:42.png"
    Content-Type: image/png
    
    
    ------WebKitFormBoundaryMmLSkbfQskfIcjfE--
    
  • Tyler Buchea
    Tyler Buchea over 10 years
    request returns an array of files so try. console.log("files", request.files); Thanks for the great answer. Worked like a charm.
  • Eugene Krevenets
    Eugene Krevenets over 10 years
    github.com/senchalabs/connect/wiki/Connect-3.0 express.bodyParser is depricated
  • Leonid Glanz
    Leonid Glanz over 8 years
    Welcome to Stackoverflow, if you want to answer to a question, then you should consider the case of the questioner.
  • frustrated-dev
    frustrated-dev almost 4 years
    @robert mitchell I have trouble related to this issue but on multer framework stackoverflow.com/questions/63218454/…