1

I am new to js/reactjs/nodejs and I am implementing a feature to allow a user to choose a file manually and upload it to a test local ftp server (in directory /test). The issue i am having is that the ftp.upload function takes a String for the full path of the file being uploaded, but I am not explicitly giving the path because the file is chosen via a "Browse files" button.

It works perfectly if I test without ftp (locally), but I can't seem to upload the file from the request onto a FTP-Server. If I add a full path to the file which I want to upload, it seems to work but that ruins the purpose of choosing a file to upload and uploading after clicking on Upload

This is the server.js

const express = require("express"); const fileUpload = require("express-fileupload"); const app = express(); var EasyFtp = require("easy-ftp"); var ftp = new EasyFtp(); app.use(fileUpload()); var config = { host: "127.0.0.1", type: "FTP", port: "", username: "admin", password: "", }; ftp.connect(config); app.post("/upload", (req, res) => { console.log(req.files); if (req.files === null) { return res.status(400).json({ msg: "No file was uploaded" }); //no file uploaded } const file = req.files.file; ftp.upload(file, "/test", function (err) { if (err) { console.log(err); return res.status(500).send(err); } else { console.log("finished:", res); res.json({ fileName: file.name, filePath: `/upload/${file.name}` }); } }); // res.json({ fileName: file.name, filePath: `/uploads/${file.name}` }); }); ftp.mv( `/test/(${ (file.tempFilePath.split("/").at(-1), file.name, function (err, newPath) {}) })` ); ftp.close(); const PORT = process.env.PORT || 5000; app.listen(PORT, () => console.log(`server started on port ${PORT}`)); 

This is the FileUpload file

import React, { Fragment, useState } from "react"; import axios from "axios"; import Message from "./Message"; import Progress from "./Progress"; const FileUpload = () => { //actual file and filename should go into state because the label "Choose File" needs to be replaced with the actual filename const [files, setFile] = useState(""); const [filename, setFilename] = useState("Choose File..."); const [uploadedFiles, setUploadedFiles] = useState({}); const [message, setMessage] = useState(""); const [uploadPercent, setUploadPercent] = useState(0); const onChange = (e) => { setFile(e.target.files[0]); let x = []; for (let file of e.target.files) { x.push(file.name); } setFilename(x); }; const onSubmit = async (e) => { e.preventDefault(); //add the file to form data const formData = new FormData(); formData.append("file", files); try { const response = await axios.post("/upload", formData, { headers: { "Content-Type": "multipart/form-data", }, //progress bar for upload onUploadProgress: (progressEvent) => { setUploadPercent( parseInt( //get rid of progress bar after 10 seconds of finished upload Math.round((progressEvent.loaded * 100) / progressEvent.total) ) ); setTimeout(() => setUploadPercent(0), 1000); }, //clear loaded percentage bar }); const { fileName, filePath } = response.data; setUploadedFiles({ fileName, filePath }); setMessage("File uploaded successfully"); } catch (error) { if (error.response.status === 500) { setMessage("There was a problem with the server, please try again."); } else { setMessage(error.response.data.msg); } } }; return ( <Fragment> {message ? <Message msg={message} /> : null} <form onSubmit={onSubmit}> <div className="custom-file"> <input type="file" className="custom-file-input" id="customFile" onChange={onChange} multiple /> <label className="custom-file-label" htmlFor="customFile"> {filename} </label> </div> <Progress percentage={uploadPercent} /> <input type="submit" value="Upload" className="btn btn-primary btn-block mt-4" /> </form> </Fragment> ); }; export default FileUpload; 

Is there any way to correct this? What am I missing? If more code snippets are required please let me know!

UPDATE!!


ftp.mv not doing anything

app.post("/upload", (req, res) => { console.log(req.files); if (req.files === null) { return res.status(400).json({ msg: "No file was uploaded" }); //error message if no file was uploaded } const file = req.files.file; const tempFileName = file.tempFilePath.split("/").at(-1); ftp.upload(file.tempFilePath, "/test", function (err) { if (err) { console.log(err); return res.status(500).send(err); } else { console.log("finished:", res); res.json({ fileName: file.name, filePath: `/uploads/${file.name}`, }); } }); ftp.mv(`/test/${tempFileName}`, "abc", function (err, newPath) {}); ftp.close(); }); 

1 Answer 1

1

You are sending a file to the server, you need to save it momentarily and upload it from there, start by changing your fileUpload configuration to this:

 app.use(fileUpload({ useTempFiles : true, tempFileDir : '/tmp/' })); 

Then you can upload the file by accessing its temporary file path:

app.post("/upload", (req, res) => { console.log(req.files); if (req.files === null) { return res.status(400).json({ msg: "No file was uploaded" }); //no file uploaded } const file = req.files.file; // here we access the temporary file path ftp.upload(file.tempFilePath, "/test", function (err) { if (err) { console.log(err); return res.status(500).send(err); } else { console.log("finished:", res); res.json({ fileName: file.name, filePath: `/upload/${file.name}` }); } ftp.close(); }); }); }); 
Sign up to request clarification or add additional context in comments.

12 Comments

Where you define your proxy for axios, try to add a forward slash, http://localhost:5000/
just to see if it works, could you try to just use localhost:5000 in your client axios call?
ahh that worked! Thatts amazing! Last issue im seeing is that the file was renamed to: tmp-1-1655998003097but originally it was a pdf. Is there a way to change this?
you can use ftp.mv to rename the file to the old name
you are uploading at /test/ in your ftp instance, so do this after upload, ftp.mv(/test/${file.tempFilePath.split("/").at(-1), "abc", function(err, newPath){}};
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.