Riky
Riky

Reputation: 55

send data from client (reactjs) to server (nodejs) but empty

hi guys i try to upload file from react-nodejs to google clode storage , in client when i upload file and console log the file , it show the file array but when i try to send to server side , the array is empty

this is client

const [myFile, setmyFile] = useState("");

  const onFileUpload = () => {
    console.log(myFile);
    Axios.post("http://localhost:10000/uploads", { myFile: myFile });
  };

<div>
        <h1>GeeksforGeeks</h1>
        <h3>File Upload using React!</h3>
        <div>
          <input
            type="file"
            onChange={(event) => {
              setmyFile(event.target.files[0]);
            }}
          />
          <button onClick={onFileUpload}>Upload!</button>
        </div>

this is server

app.post("/uploads", async (req, res, next) => {
  try {
    const myFile = req.body.myFile;
    console.log(myFile);
    const imageUrl = await uploadImage(myFile);
    res.status(200).json({
      message: "Upload was successful",
      data: imageUrl,
    });
  } catch (error) {
    next(error);
  }
});

can someone help me , why "myFile" return "{}"

Upvotes: 0

Views: 1435

Answers (3)

Jose V
Jose V

Reputation: 1496

As @Akanksha singh mentioned, you need to set the Content-Type header to multipart/form-data and use the formData object on the client side:

const onFileUpload = () => {
  console.log(myFile);
  try {
    const formData = new FormData()
    formData.append('file', myFile)

    Axios.post("http://localhost:10000/uploads", formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
  } catch (error) {
    console.error('Error while uploading image to server', error)
  }
};

<div>
 <h1> GeeksforGeeks </h1> <h3 > File Upload using React! </h3>
 <div>
  <input
    type="file"
    onChange={
      (event) => {
        setmyFile(event.target.files[0]);
      }
    }
  />
  <button onClick={onFileUpload}> Upload! </button>
 </div>
</div>

After testing this, logging the req.body on the server side returns a buffer instead of an empty object.

In order to deal with this buffer, which contains the form data, I suggest you follow the steps mentioned in the official docs to deal with multipart/form-data in Cloud Functions

Here is the code sample from the docs:

/**
 * Parses a 'multipart/form-data' upload request
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
const path = require('path');
const os = require('os');
const fs = require('fs');

// Node.js doesn't have a built-in multipart/form-data parsing library.
// Instead, we can use the 'busboy' library from NPM to parse these requests.
const Busboy = require('busboy');

exports.uploadFile = (req, res) => {
  if (req.method !== 'POST') {
    // Return a "method not allowed" error
    return res.status(405).end();
  }
  const busboy = new Busboy({headers: req.headers});
  const tmpdir = os.tmpdir();

  // This object will accumulate all the fields, keyed by their name
  const fields = {};

  // This object will accumulate all the uploaded files, keyed by their name.
  const uploads = {};

  // This code will process each non-file field in the form.
  busboy.on('field', (fieldname, val) => {
    /**
     *  TODO(developer): Process submitted field values here
     */
    console.log(`Processed field ${fieldname}: ${val}.`);
    fields[fieldname] = val;
  });

  const fileWrites = [];

  // This code will process each file uploaded.
  busboy.on('file', (fieldname, file, filename) => {
    // Note: os.tmpdir() points to an in-memory file system on GCF
    // Thus, any files in it must fit in the instance's memory.
    console.log(`Processed file ${filename}`);
    const filepath = path.join(tmpdir, filename);
    uploads[fieldname] = filepath;

    const writeStream = fs.createWriteStream(filepath);
    file.pipe(writeStream);

    // File was processed by Busboy; wait for it to be written.
    // Note: GCF may not persist saved files across invocations.
    // Persistent files must be kept in other locations
    // (such as Cloud Storage buckets).
    const promise = new Promise((resolve, reject) => {
      file.on('end', () => {
        writeStream.end();
      });
      writeStream.on('finish', resolve);
      writeStream.on('error', reject);
    });
    fileWrites.push(promise);
  });

  // Triggered once all uploaded files are processed by Busboy.
  // We still need to wait for the disk writes (saves) to complete.
  busboy.on('finish', async () => {
    await Promise.all(fileWrites);

    /**
     * TODO(developer): Process saved files here
     */
    for (const file in uploads) {
      fs.unlinkSync(uploads[file]);
    }
    res.send();
  });

  busboy.end(req.rawBody);
};

Upvotes: 1

Akanksha singh
Akanksha singh

Reputation: 151

In client side you have to add your file to formData object, and set the Content-Type header to multipart/form-data.

Client side code -


const onFileUpload = () => {
  console.log(myFile);
  try {
    const formData = new FormData()
    formData.append('file', myFile)

    Axios.post("http://localhost:10000/uploads", formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
  } catch (error) {
    console.error('Error while uploading image to server', error)
  }
};

<div>
 <h1> GeeksforGeeks </h1> <h3 > File Upload using React! </h3>
 <div>
  <input
    type="file"
    onChange={
      (event) => {
        setmyFile(event.target.files[0]);
      }
    }
  />
  <button onClick={onFileUpload}> Upload! </button>
 </div>
</div>

Server side:

  1. You have to use multer or some other npm package to upload the files in the server side.
  2. Once image is uploaded to google cloud storage, delete the file from local disk. finally block in below code is deleting the file from local disk once image is uploaded successfully or if there is any error in uploading the image.
const multer = require('multer')
const fs = require('fs')

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'public')
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + '-' + file.originalname)
  }
})

const upload = multer({ storage: storage }).single('file')

app.post("/uploads", async (req, res, next) => {

  upload(req, res, async function (error) {
    if (error instanceof multer.MulterError) {
      return res.status(500).json(error)
    } else if (error) {
      return res.status(500).json(error)
    }
    const { filename } = req.file
    var fileStream = fs.createReadStream(req.file.path)
    try {
      const options = {
        filename
      }
      const imageUrl = await uploadImage(fileStream, options)
      res.status(200).json({
        message: "Upload was successful",
        data: imageUrl,
      });
    } catch (error) {
      next(error);
    } finally {
      fs.unlink(req.file.path, function (error) {
        if (error) {
          console.log('Error on deleting file from the path: ', req.file.path)
        }
        console.log('File deleted successfully from the disk')
      })
    }
  })
});


Upvotes: 1

Ntshembo Hlongwane
Ntshembo Hlongwane

Reputation: 1051

Simple way of file uploading with react to node sever is.

On React here is how you want to handle things using axios

const data = new FormData();
data.append('media_file', file_input) // Note the file in quotes is the key that the server will use to retrive the input i.e **file_input** in this case

axios.post(url, data).then(res=>{
    console.log(res)
}).catch(error=>{
    console.log(error)
})

So now how you handle this on your nodejs is like this I will be using formidable as bodyParser very easy to use

const Formidable = require("formidable"); //Meant for body parsing

router.post('/api/file-upload', (req, res)=>{
    const form = new Formidable.InconmingForm();
    form.parse(req, (error, fields, files)=>{
        const {media_file} = files 
        //Destructing 'media_file' remember name that we stated on the client
        // it was 'media_file' now that is what I want to de-structure within files which comes 
        //with formidable

    })

})

So now if you log media_file you will see all that you need about file then you can continue with your logic of uploading to google cloud

Upvotes: 1

Related Questions