最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to send a file in array of object to express server? - Stack Overflow

programmeradmin1浏览0评论

I have an array of the object, each object contains some properties of type string and a file.

This is how my array looks like:

const args = [
    {
        name: 'presentation',
        price: 9.99,
        tags: 'invest, finance, business',
        file: File,
        thumbnail: File
    },
    {
        name: 'presentation2',
        price: 20.99,
        tags: 'invest, finance, business',
        file: File,
        thumbnail: File
    }
]

const headers = {
 headers: {
   Authorization: `Bearer ${token}`
 }
};

My goal is to send this whole array of the object to the Express Server. there I will save information to the Mongo and upload the file to S3. But Currently, I am unable to get the file stream on the server when I send this in a POST request, even the whole req.body is an empty object when I console.log it

axios.post(`${slidesRoute}/createSlides`, args, headers);

Alternatively, I tried to put everything into FormData. for example:

let formData = new FormData();
    selectedFiles.forEach((selectedFile, i) => {
        formData.append(`name_${i}`, selectedFile.name);
        formData.append(`price_${i}`, selectedFile.price);
        formData.append(`tags_${i}`, selectedFile.tags);
        formData.append(`file_${i}`, selectedFile.file);
        formData.append(`thumbnail_${i}`, selectedFile.thumbnail);
    });
axios.post(`${slidesRoute}/createSlides`, formData, headers);

Then In the backend. I am unable to catch these files using multer. Because the filenames in form data are being generated dynamically like

file_1, file_2 file_3,...

But multer expects the exact filename to be passed for example multer().array('file')

so in my second approach I am unable to catch files using Multer

I have an array of the object, each object contains some properties of type string and a file.

This is how my array looks like:

const args = [
    {
        name: 'presentation',
        price: 9.99,
        tags: 'invest, finance, business',
        file: File,
        thumbnail: File
    },
    {
        name: 'presentation2',
        price: 20.99,
        tags: 'invest, finance, business',
        file: File,
        thumbnail: File
    }
]

const headers = {
 headers: {
   Authorization: `Bearer ${token}`
 }
};

My goal is to send this whole array of the object to the Express Server. there I will save information to the Mongo and upload the file to S3. But Currently, I am unable to get the file stream on the server when I send this in a POST request, even the whole req.body is an empty object when I console.log it

axios.post(`${slidesRoute}/createSlides`, args, headers);

Alternatively, I tried to put everything into FormData. for example:

let formData = new FormData();
    selectedFiles.forEach((selectedFile, i) => {
        formData.append(`name_${i}`, selectedFile.name);
        formData.append(`price_${i}`, selectedFile.price);
        formData.append(`tags_${i}`, selectedFile.tags);
        formData.append(`file_${i}`, selectedFile.file);
        formData.append(`thumbnail_${i}`, selectedFile.thumbnail);
    });
axios.post(`${slidesRoute}/createSlides`, formData, headers);

Then In the backend. I am unable to catch these files using multer. Because the filenames in form data are being generated dynamically like

file_1, file_2 file_3,...

But multer expects the exact filename to be passed for example multer().array('file')

so in my second approach I am unable to catch files using Multer

Share Improve this question edited Jan 2, 2020 at 18:15 Waeez asked Dec 31, 2019 at 20:11 WaeezWaeez 3394 gold badges13 silver badges29 bronze badges 2
  • could you please attach server-side code – Alex Commented Jan 4, 2020 at 7:01
  • 1 You need to add your server-side handling logic or the question is not answerable! – Mattia Rasulo Commented Jan 6, 2020 at 8:41
Add a ment  | 

3 Answers 3

Reset to default 5

You can't include file inside JSON. File is not JSON-serializable. Ideally you should have a separate endpoint to accept your files, send them with content-type: multipart/form-data, receive unique id for that file stored on the server, then send your JSON with ids instead of files.

As a chaper alternative you can Base64 encode your files into a string, insert this string in your request, and then decode it back on the receiving side

FormData key values are array by default in your code Just change

formData.append(`file_${i}`, selectedFile.file);

to

formData.append(`file`, selectedFile.file);

You should be able to receive the file array in server side using multer().array('file')

Sample below demonstrating FormData key values array behavior

const formData = new FormData();
formData.append('key1', 'value1');
formData.append('key1', 'value2');
formData.append('key2', 'value1');

formData.forEach(function(value, key){ 
    console.log(key, value);
    
});

I use FormData to send a number of files - and then on the node.js server I use Formidable.

I've pasted some partial code below that may help - sorry it's not a smaller sample.

Hope it helps

On the browser side I have:

let form_data = new FormData()
form_data.append('upload_data', file)
$.ajax({
  url: '/file/upload' + remote_path + '/' + filename,
  type: 'POST',
  data: form_data,
  processData: false,
  contentType: false,
  success: (res) => {
...

On the node.js side (apologies for the length..)I have:

const fs = require('fs')
const formidable = require('formidable')
const path = require('path')
...
app.post('/file/upload/*', (req, res) => {
let filename = req.params[0]
let media = path.basename(filename)
let folder = filename.substring(0, filename.length - media.length)
let form = new formidable.IningForm()
// form.encoding = 'utf-8'
form.multiples = true
form.uploadDir = path.join(media_folder, folder)
form.keepExtensions = true
form.parse(req, (err, fields, files) => {
  if (err) {
    fail(res, 'failed to upload')
  } else {
    success(res)
  }
})
form.on('fileBegin', (name, file) => {
  const [fileName, fileExt] = file.name.split('.')
  file.path = path.join(form.uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
})
form.on('file', (field, file) => {
  fs.rename(file.path, path.join(form.uploadDir, file.name), (err) => {
    if (!res.headersSent) { // Fix since first response is received
      fail(res, 'an error has occured with form upload' + err)
    }
  })
})
form.on('error', (err) => {
  fail(res, 'an error has occured with form upload' + err)
})
form.on('aborted', (err) => {
  fail(res, 'Upload cancelled by browser')
})

})

发布评论

评论列表(0)

  1. 暂无评论