简体   繁体   中英

Nodejs - how can I save a file object sent from frontend to the public folder without using middleware like multer?

I have a React client side app and a Nodejs backend.

I am trying to sent a stringified json and some pdf files (uploaded from the client side by react-dropzone ) as formdata/multipart in a put request like this:

let formData = new FormData()

formData.append('user', JSON.stringify(jsonData))
formData.append('file_1', user.file_1)
formData.append('file_2', user.file_2)

In my Nodejs backend, I extract the form data with multer:

let multerInstance = multer();
userRouter.put('/user/:user_id', validateJwt, multerInstance.any(), putUser);

and I extract the formdata like this:

const formData = req.body;
const user = JSON.parse(formData.user);
const files = req.files; // here I have file_1 and file_2 as file objects

however, if I use multer to save the files, I have to pass the config settings in the middleware like this:

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './public/uploads');
  },
  filename: function (req, file, cb) {
    var fileFormat = file.originalname.split('.');
    cb(null, file.fieldname + '-' + Date.now() + '.' + fileFormat[fileFormat.length - 1]);
  },
});

let multerInstance = multer({
  storage: storage,
});

let multerInstance = multer();
userRouter.put('/user/:user_id', validateJwt, multerInstance.any(), putUser);

which I don't want to, because I want to decide whether to do the upload action (save to /public/uploads) inside putUser, instead of setting the destination in the multer middleware (which will run before putUser, no matter what)

how can I achieve this?

Glad to figured out the solution using fs.writeFile

First, use multer on the route like this without any configuration so that it only works as a formdata phaser:

let multerInstance = multer();
userRouter.put('/user/:user_id', validateJwt, multerInstance.any(), putUser);

Next, obtain the files with req.files in the route, files that phased by multer will look like this:

{
    fieldname: 'myField',
    originalname: 'file_1.pdf',
    encoding: '7bit',
    mimetype: 'application/pdf',
    buffer: <Buffer 25 50 44 46 2d 31 2e 33 0a 25 c4 e5 f2 e5 eb a7 f3 a0 d0 c4 c6 0a 34 20 30 20 6f 62 6a 0a 3c 3c 20 2f 4c 65 6e 67 74 68 20 35 20 30 20 52 20 2f 46 69 ... 51728 more bytes>,
    size: 51778
}

Since I observe that there's a buffer in the file, I can write the file to the target path using the fs module so that the upload action can be done inside the route.

const files = req.files

const uploadFiles = files.map((file) => {
   return new Promise(function (resolve, reject) {
       let fileFormat = file.originalname.split('.');
       let savePath = file.fieldname + '-' + Date.now() + '.' + fileFormat[fileFormat.length - 1];
       fs.writeFile('./public/uploads/' + savePath, file.buffer, function (err) {
         if (err) {
            return reject();
         }

         return resolve();
      });
   });
});

await Promise.all(uploadFiles);

You can configure multer and only call it from inside of putUser() when you are ready. If you supply your own next() function to the middleware instead of the standard one, it will call your function when it's done rather than the next route.

You need software to read the body and parse the multipart mime and it's not fun to write that yourself which is why I recommend you use existing software for the parsing.

Here's a general idea for how that could look:

function putUser(req, res, next) {
    // do a bunch of your own logic here
    if (iWantToProcessFile) {
        // call multer middleware to process form data
        let multerFn = multerInstance.any();
        multerFn(req, res, function(err) {
            if (err) return next(err);
            // use multer data on req object now to finish your request
        });
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM